@@ -63,6 +63,14 @@ func (s *composeService) start(ctx context.Context, projectName string, options
6363 return s .watchContainers (context .Background (), project .Name , options .AttachTo , options .Services , listener , attached ,
6464 func (container moby.Container , _ time.Time ) error {
6565 return s .attachContainer (ctx , container , listener )
66+ }, func (container moby.Container , _ time.Time ) error {
67+ listener (api.ContainerEvent {
68+ Type : api .ContainerEventAttach ,
69+ Container : "" , // actual name will be set by start event
70+ ID : container .ID ,
71+ Service : container .Labels [api .ServiceLabel ],
72+ })
73+ return nil
6674 })
6775 })
6876 }
@@ -114,7 +122,7 @@ type containerWatchFn func(container moby.Container, t time.Time) error
114122// watchContainers uses engine events to capture container start/die and notify ContainerEventListener
115123func (s * composeService ) watchContainers (ctx context.Context , //nolint:gocyclo
116124 projectName string , services , required []string ,
117- listener api.ContainerEventListener , containers Containers , onStart containerWatchFn ) error {
125+ listener api.ContainerEventListener , containers Containers , onStart , onRecreate containerWatchFn ) error {
118126 if len (containers ) == 0 {
119127 return nil
120128 }
@@ -123,12 +131,13 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
123131 }
124132
125133 var (
126- expected Containers
134+ expected [] string
127135 watched = map [string ]int {}
136+ replaced []string
128137 )
129138 for _ , c := range containers {
130139 if utils .Contains (required , c .Labels [api .ServiceLabel ]) {
131- expected = append (expected , c )
140+ expected = append (expected , c . ID )
132141 }
133142 watched [c .ID ] = 0
134143 }
@@ -157,23 +166,38 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
157166 service := container .Labels [api .ServiceLabel ]
158167 switch event .Status {
159168 case "stop" :
160- listener (api.ContainerEvent {
161- Type : api .ContainerEventStopped ,
162- Container : name ,
163- Service : service ,
164- })
169+ if _ , ok := watched [container .ID ]; ok {
170+ eType := api .ContainerEventStopped
171+ if utils .Contains (replaced , container .ID ) {
172+ utils .Remove (replaced , container .ID )
173+ eType = api .ContainerEventRecreated
174+ }
175+ listener (api.ContainerEvent {
176+ Type : eType ,
177+ Container : name ,
178+ ID : container .ID ,
179+ Service : service ,
180+ })
181+ }
165182
166183 delete (watched , container .ID )
167- expected = expected . remove ( container .ID )
184+ expected = utils . Remove ( expected , container .ID )
168185 case "die" :
169186 restarted := watched [container .ID ]
170187 watched [container .ID ] = restarted + 1
171188 // Container terminated.
172189 willRestart := inspected .State .Restarting
173190
191+ eType := api .ContainerEventExit
192+ if utils .Contains (replaced , container .ID ) {
193+ utils .Remove (replaced , container .ID )
194+ eType = api .ContainerEventRecreated
195+ }
196+
174197 listener (api.ContainerEvent {
175- Type : api . ContainerEventExit ,
198+ Type : eType ,
176199 Container : name ,
200+ ID : container .ID ,
177201 Service : service ,
178202 ExitCode : inspected .State .ExitCode ,
179203 Restarting : willRestart ,
@@ -182,15 +206,15 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
182206 if ! willRestart {
183207 // we're done with this one
184208 delete (watched , container .ID )
185- expected = expected . remove ( container .ID )
209+ expected = utils . Remove ( expected , container .ID )
186210 }
187211 case "start" :
188212 count , ok := watched [container .ID ]
189213 mustAttach := ok && count > 0 // Container restarted, need to re-attach
190214 if ! ok {
191215 // A new container has just been added to service by scale
192216 watched [container .ID ] = 0
193- expected = append (expected , container )
217+ expected = append (expected , container . ID )
194218 mustAttach = true
195219 }
196220 if mustAttach {
@@ -200,6 +224,21 @@ func (s *composeService) watchContainers(ctx context.Context, //nolint:gocyclo
200224 return err
201225 }
202226 }
227+ case "create" :
228+ if id , ok := container .Labels [api .ContainerReplaceLabel ]; ok {
229+ replaced = append (replaced , id )
230+ err = onRecreate (container , event .Timestamp )
231+ if err != nil {
232+ return err
233+ }
234+ if utils .StringContains (expected , id ) {
235+ expected = append (expected , inspected .ID )
236+ }
237+ watched [container .ID ] = 1
238+ if utils .Contains (expected , id ) {
239+ expected = append (expected , container .ID )
240+ }
241+ }
203242 }
204243 if len (expected ) == 0 {
205244 stop ()
0 commit comments