@@ -153,7 +153,7 @@ func (fr *FFmpegRecorder) Start(ctx context.Context) error {
153153 go fr .waitForCommand (ctx )
154154
155155 // Check for startup errors before returning
156- if err := waitForChan (ctx , 500 * time .Millisecond , fr .exited ); err == nil {
156+ if err := waitForChan (ctx , 250 * time .Millisecond , fr .exited ); err == nil {
157157 fr .mu .Lock ()
158158 defer fr .mu .Unlock ()
159159 return fmt .Errorf ("failed to start ffmpeg process: %w" , fr .ffmpegErr )
@@ -165,16 +165,17 @@ func (fr *FFmpegRecorder) Start(ctx context.Context) error {
165165// Stop gracefully stops the recording using a multi-phase shutdown process.
166166func (fr * FFmpegRecorder ) Stop (ctx context.Context ) error {
167167 return fr .shutdownInPhases (ctx , []shutdownPhase {
168- {"interrupt" , []syscall.Signal {syscall .SIGCONT , syscall .SIGINT }, 5 * time .Second , "graceful stop" },
169- {"terminate" , []syscall.Signal {syscall .SIGTERM }, 2 * time .Second , "forceful termination" },
170- {"kill" , []syscall.Signal {syscall .SIGKILL }, 1 * time .Second , "immediate kill" },
168+ {"wake_and_interrupt" , []syscall.Signal {syscall .SIGCONT , syscall .SIGINT }, 5 * time .Second , "graceful stop" },
169+ {"retry_interrupt" , []syscall.Signal {syscall .SIGINT }, 3 * time .Second , "retry graceful stop" },
170+ {"terminate" , []syscall.Signal {syscall .SIGTERM }, 250 * time .Millisecond , "forceful termination" },
171+ {"kill" , []syscall.Signal {syscall .SIGKILL }, 100 * time .Millisecond , "immediate kill" },
171172 })
172173}
173174
174175// ForceStop immediately terminates the recording process.
175176func (fr * FFmpegRecorder ) ForceStop (ctx context.Context ) error {
176177 return fr .shutdownInPhases (ctx , []shutdownPhase {
177- {"kill" , []syscall.Signal {syscall .SIGKILL }, 1 * time .Second , "immediate kill" },
178+ {"kill" , []syscall.Signal {syscall .SIGKILL }, 100 * time .Millisecond , "immediate kill" },
178179 })
179180}
180181
@@ -321,6 +322,7 @@ func (fr *FFmpegRecorder) shutdownInPhases(ctx context.Context, phases []shutdow
321322
322323 pgid := - cmd .Process .Pid // negative PGID targets the whole group
323324 for _ , phase := range phases {
325+ phaseStartTime := time .Now ()
324326 // short circuit: the process exited before this phase started.
325327 select {
326328 case <- done :
@@ -331,12 +333,16 @@ func (fr *FFmpegRecorder) shutdownInPhases(ctx context.Context, phases []shutdow
331333 log .Info ("ffmpeg shutdown phase" , "phase" , phase .name , "desc" , phase .desc )
332334
333335 // Send the phase's signals in order.
334- for _ , sig := range phase .signals {
336+ for idx , sig := range phase .signals {
335337 _ = syscall .Kill (pgid , sig ) // ignore error; process may have gone away
338+ // arbitrary delay between signals, but not after the last signal
339+ if idx < len (phase .signals )- 1 {
340+ time .Sleep (100 * time .Millisecond )
341+ }
336342 }
337343
338344 // Wait for exit or timeout
339- if err := waitForChan (ctx , phase .timeout , done ); err == nil {
345+ if err := waitForChan (ctx , phase .timeout - time . Since ( phaseStartTime ) , done ); err == nil {
340346 log .Info ("ffmpeg shutdown successful" , "phase" , phase .name )
341347 return nil
342348 }
0 commit comments