{"record":{"id":"24811ad3f94b0048","repo":"hibiken/asynq","slug":"asynq-the-server-is-already-running","errorCode":null,"errorMessage":"asynq: the server is already running","messagePattern":"asynq: the server is already running","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server.go","lineNumber":710,"sourceCode":"\tsrv.healthchecker.start(&srv.wg)\n\tsrv.subscriber.start(&srv.wg)\n\tsrv.syncer.start(&srv.wg)\n\tsrv.recoverer.start(&srv.wg)\n\tsrv.forwarder.start(&srv.wg)\n\tsrv.processor.start(&srv.wg)\n\tsrv.janitor.start(&srv.wg)\n\tsrv.aggregator.start(&srv.wg)\n\treturn nil\n}\n\n// Checks server state and returns an error if pre-condition is not met.\n// Otherwise it sets the server state to active.\nfunc (srv *Server) start() error {\n\tsrv.state.mu.Lock()\n\tdefer srv.state.mu.Unlock()\n\tswitch srv.state.value {\n\tcase srvStateActive:\n\t\treturn fmt.Errorf(\"asynq: the server is already running\")\n\tcase srvStateStopped:\n\t\treturn fmt.Errorf(\"asynq: the server is in the stopped state. Waiting for shutdown.\")\n\tcase srvStateClosed:\n\t\treturn ErrServerClosed\n\t}\n\tsrv.state.value = srvStateActive\n\treturn nil\n}\n\n// Shutdown gracefully shuts down the server.\n// It gracefully closes all active workers. The server will wait for\n// active workers to finish processing tasks for duration specified in Config.ShutdownTimeout.\n// If worker didn't finish processing a task during the timeout, the task will be pushed back to Redis.\nfunc (srv *Server) Shutdown() {\n\tsrv.state.mu.Lock()\n\tif srv.state.value == srvStateNew || srv.state.value == srvStateClosed {\n\t\tsrv.state.mu.Unlock()\n\t\t// server is not running, do nothing and return.","sourceCodeStart":692,"sourceCodeEnd":728,"githubUrl":"https://github.com/hibiken/asynq/blob/d135f1439bee74e989b7f9b41ecd542cc87f024a/server.go#L692-L728","documentation":"Server.start enforces a single active server per Server instance. If Start (or Run) is invoked while the server's state is already Active, this error is returned because a server can process tasks from only one handler loop at a time.","triggerScenarios":"Calling srv.Start(handler) or srv.Run(handler) a second time without calling Stop/ShutDown first; calling both Run and Start on the same Server; restart logic that forgot the previous Start succeeded.","commonSituations":"Code paths that construct-or-reuse a shared Server singleton and call Start on every request; hot-reload logic restarting the server; duplicate startup in tests with shared fixtures.","solutions":["Call Start (or Run) only once per Server instance; keep the returned state and reuse it.","If you need to restart, call Stop() (and eventually ShutDown()) first, and create a new Server if it was closed.","Track server lifecycle with a separate mutex/flag in application code, or check srv state before starting.","Create a new asynq.Server instead of reusing a running one."],"exampleFix":"// before\nsrv.Start(handler)\n...\nsrv.Start(handler) // panics: already running\n// after\nif err := srv.Start(handler); err != nil && !strings.Contains(err.Error(), \"already running\") {\n    log.Fatal(err)\n}","handlingStrategy":"validation","validationCode":"var startOnce sync.Once\nfunc ensureStarted(srv *asynq.Server, h asynq.Handler) error {\n    var err error\n    startOnce.Do(func() { err = srv.Start(h) })\n    return err\n}","typeGuard":null,"tryCatchPattern":"if err := srv.Start(handler); err != nil {\n    if strings.Contains(err.Error(), \"already running\") {\n        return nil // idempotent start\n    }\n    return err\n}","preventionTips":["Start each Server exactly once (sync.Once or a lifecycle manager).","Never share one asynq.Server across independent start paths.","On restart, always create a new Server instance."],"tags":["go","asynq","lifecycle","double-start"],"backgroundTag":"invalid-state-transition","analyzedSha":"d135f1439bee74e989b7f9b41ecd542cc87f024a","analyzedAt":"2026-09-07T19:02:34.660Z","contentChangedAt":"2026-09-07T19:02:34.660Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}