Skip to content

Commit 7c09851

Browse files
Fix Docker container exit issue with improved error handling and signal processing (#44)
Co-authored-by: Fedor Batonogov <f.batonogov@yandex.ru>
1 parent 5119e4a commit 7c09851

File tree

1 file changed

+50
-2
lines changed

1 file changed

+50
-2
lines changed

main.go

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import (
55
"log"
66
"os"
77
"os/exec"
8+
"os/signal"
89
"strconv"
910
"strings"
11+
"syscall"
1012
"time"
1113
)
1214

@@ -264,12 +266,21 @@ var defaultCommandRunner CommandRunner = &RealCommandRunner{}
264266
func executeCommand(command string) {
265267
log.Printf("Running command: %s", command)
266268

269+
// Check if bash exists, fallback to sh if not
270+
shell := "/bin/bash"
271+
if _, err := os.Stat(shell); os.IsNotExist(err) {
272+
shell = "/bin/sh"
273+
log.Printf("Bash not found, using sh instead")
274+
}
275+
267276
// u0438u0441u043fu043eu043bu044cu0437u0443u0435u043c u0438u043du0442u0435u0440u0444u0435u0439u0441 CommandRunner u0434u043bu044f u0432u043eu0437u043cu043eu0436u043du043eu0441u0442u0438 u043cu043eu043au0438u0440u043eu0432u0430u043du0438u044f
268-
output, err := defaultCommandRunner.Run("/bin/bash", "-c", command)
277+
output, err := defaultCommandRunner.Run(shell, "-c", command)
269278

270279
if err != nil {
271280
log.Printf("Error executing command %s: %v", command, err)
281+
// Don't exit, just log the error and continue
272282
}
283+
273284
log.Printf("Output from command %s: %s", command, string(output))
274285
}
275286

@@ -285,10 +296,18 @@ func createEveryTickers(tasks []*CronSchedule) []*time.Ticker {
285296

286297
for _, task := range tasks {
287298
if task.isEvery {
299+
log.Printf("Setting up @every ticker for task '%s' with interval %v", task.command, task.interval)
288300
ticker := time.NewTicker(task.interval)
289301
tickers = append(tickers, ticker)
290302

291303
go func(t *CronSchedule, tkr *time.Ticker) {
304+
// Recover from panics
305+
defer func() {
306+
if r := recover(); r != nil {
307+
log.Printf("Recovered from panic in @every ticker for '%s': %v", t.command, r)
308+
}
309+
}()
310+
292311
for range tkr.C {
293312
go executeCommand(t.command)
294313
}
@@ -321,13 +340,24 @@ func startCronScheduler(tasks []*CronSchedule) {
321340
}
322341
}()
323342

343+
// Recover from panics
344+
defer func() {
345+
if r := recover(); r != nil {
346+
log.Printf("Recovered from panic in scheduler: %v", r)
347+
}
348+
}()
349+
324350
// Main ticker for regular cron jobs
325351
ticker := time.NewTicker(time.Minute)
326352
defer ticker.Stop()
327353

354+
// Log initial startup
355+
log.Printf("Scheduler started with %d tasks", len(tasks))
356+
328357
for {
329358
select {
330359
case t := <-ticker.C:
360+
log.Printf("Running cron tasks at %s", t.Format(time.RFC3339))
331361
runCronTasks(tasks, t)
332362
}
333363
}
@@ -336,6 +366,24 @@ func startCronScheduler(tasks []*CronSchedule) {
336366
// main initializes and runs the cron scheduler.
337367
// Creates separate tickers for @every tasks and a main ticker for standard cron tasks.
338368
func main() {
369+
// Setup signal handling for graceful shutdown
370+
sigChan := make(chan os.Signal, 1)
371+
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
372+
339373
tasks := loadTasks()
340-
startCronScheduler(tasks)
374+
375+
// Start scheduler in a goroutine
376+
done := make(chan bool)
377+
go func() {
378+
startCronScheduler(tasks)
379+
done <- true
380+
}()
381+
382+
// Wait for either a signal or scheduler completion
383+
select {
384+
case sig := <-sigChan:
385+
log.Printf("Received signal %v, shutting down...", sig)
386+
case <-done:
387+
log.Printf("Scheduler completed unexpectedly")
388+
}
341389
}

0 commit comments

Comments
 (0)