All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
-
Worker isolation mode:
CONDUCTOR_WORKER_ISOLATION=threadruns every worker as a thread instead of amultiprocessing.Process(defaultprocessis unchanged —spawnremains the start method). For environments where multiprocessing's fork+exec bootstraps (spawn children,resource_tracker) fail, e.g. Firecracker microVM guests. Thread-mode tradeoffs: no per-worker force-kill (shutdown is cooperative), CPU-bound workers share the GIL, andsignal.signalbecomes a no-op off the main thread. Implementation: the Windows-only Process→Thread shim moved toconductor.client.automator.worker_isolation(the privateworker_manager._patch_conductor_use_threads_on_windowshelper is removed — the Windows gate callsapply_thread_isolation()directly) and now also swaps the logging-relayQueuefor a plainqueue.Queue -
Canonical metrics mode: opt-in harmonized metric surface via
WORKER_CANONICAL_METRICS=true-- details -
MetricsSettingsgainsclean_directoryandclean_dead_pidsfor opt-in stale.dbfile cleanup (both default toFalse) -
SchedulerClientnow carries the schedule lifecycle operations itself:pause(reason=),resume,delete,run_now,preview_next,reconcile(declarative tri-state sync) — with typed errors (ScheduleNotFound,InvalidCronExpression, ...).pause_schedulegains an optionalreason=(stored by OSS Conductor servers; ignored by Orkes servers)
- Multiprocessing start method now defaults to
spawnon all platforms (wasforkeverywhere except Windows).forkcaused silently-restartingSIGSEGVworker subprocesses on macOS (exitcode-11) and fork-with-held-lock deadlocks on POSIX. - Legacy metrics emit unchanged by default; no env var required
metrics_collector.pyis now a compatibility shim;from conductor.client.telemetry.metrics_collector import MetricsCollectorcontinues to workget_schedulereturns a typedWorkflowSchedule(orNonefor missing schedules) instead of a raw camelCase dict, matching its declared annotation and docs/SCHEDULE.md; dict-consumers should switch to attribute access orto_dict()
@worker_taskworkers are now picklable, making the decorator path work with thespawn/forkserverstart methods (fixesTypeError: cannot pickle '_thread.lock' objectandPicklingError: it's not the same object as ...; issues #264, #271):Worker.api_clientis created lazily in the worker process, runtime state (locks, pending async tasks, background loop) is excluded from pickling and rebuilt in the child, and decorated functions are pickled as importable references resolved in the childTaskHandler.start_processes()no longer hangs the interpreter when a worker fails to start (e.g., unpicklable state underspawn); it now cleans up already-started subprocesses and raises with actionable guidance- Worker processes killed by a signal now log a diagnostic hint (signal number,
PYTHONFAULTHANDLER=1guidance) instead of restarting silently - Per-schedule pause/resume now work on both Conductor server families: the client sends
PUT(the OSS Conductor dialect — the spec-generatedGETfailed there) and transparently falls back toGETon a 405 for Orkes servers