Migrating to the 3.0 major release¶
sosw skipped the 1.x and 2.x lines on purpose: the jump from 0.7.x straight to 3.0 marks a
change of what the package is. It began as the Serverless Orchestrator of Serverless Workers —
a self-hosted layer that queued, invoked, throttled and retried “Worker” Lambdas. Over the years
the parts everybody actually reused were the foundations underneath: the
Processor base class, the warm start machinery, the
components and the helpers. Meanwhile AWS shipped managed services that do the
orchestration itself better than a self-hosted queue: Step Functions, EventBridge Scheduler, SQS,
and — since 2025 — durable functions.
sosw is a framework for bootstrapping AWS Lambda functions. The self-hosted orchestration layer is removed in the 3.0 major release: it is not deprecated-but-present — it is gone.
If you landed here from an AttributeError naming a removed entity, this page tells you exactly
what to do.
TL;DR¶
Your Lambdas built on
Processor/get_lambda_handler/LambdaGlobals, the components and the helpers: nothing to do. That is the product now.Your functions built on the orchestration layer (
Orchestrator,Scheduler,Scavenger,Worker…): pin the previous line —pip install 'sosw<3'— and plan the move to AWS Step Functions, EventBridge Scheduler or durable functions.Read Behavior changes in this major release — long-standing bugs were fixed and the packaging was modernized; the fixes are the only intentional behavior differences in the remaining code.
The orchestration layer is removed¶
These entities no longer exist in the package:
sosw.Orchestrator,sosw.Scheduler,sosw.Scavenger,sosw.Worker,sosw.WorkerAssistant,sosw.Labourer,sosw.Essential,the whole
sosw.managerspackage (TaskManager,EcologyManager,MetaHandler).
Accessing a removed name through the package façade (from sosw import Orchestrator) raises an
AttributeError that points back to this page. Importing the removed modules directly
(import sosw.orchestrator) raises ModuleNotFoundError.
Teams that run the orchestration layer have two options:
Stay on the 0.7.x line.
pip install 'sosw<3'keeps everything working exactly as before — the 0.7.x releases remain on PyPI, and their documentation is preserved in the previous versions archive.Move to the managed AWS services (recommended for new designs) — see the mapping below.
What replaces the orchestration layer¶
Pick per use case:
Workflows with dependencies, retries, human-visible state → AWS Step Functions. State machines,
Mapstates for fan-out withMaxConcurrencythrottling, built-in retry/catch, execution history (this also covers the task audit trail).Cron and delayed invocations → Amazon EventBridge Scheduler. Replaces the every-minute polling rules and the cron duty of the removed layer.
Long-running, checkpointed, single-codebase workflows → durable functions (
pip install sosw[durable]) — the spiritual successor of the removed pattern, in-process, with per-step retry strategies and checkpoints.Simple queue-based load leveling and retries → SQS + Lambda event source mappings (batching, concurrency controls, DLQs out of the box).
Classes that subclassed the removed entities can usually be rebased on plain
sosw.app.Processor: the base lifecycle (config, clients, stats) is the same — only the
task-queue integration calls disappear.
Behavior changes in this major release¶
Beyond the removal, this major release ships exactly these intentional changes:
- 1. The explicit ``test`` flag is honored — in both directions.
An operator-precedence bug (
kwargs.get('test') or True if ... else False) made the resolver ignore an explicitly passed flag entirely: an explicittest=Falsewas forced toTrueintest/autoteststages, and an explicittest=Truewas forced toFalsein production stages. Now an explicit flag (thetestkwarg of the Processor, or thetestkey of the Lambda event) always wins; only when absent is the flag derived fromSTAGE. Audit any code that (accidentally) relied on the old inversion — e.g. passingtest=Truein production and counting on it being ignored.- 2. ``reset_stats()`` runs once per invocation, not twice.
The generated
lambda_handlerused to callreset_stats()twice per invocation (non-recursive, then recursive). It now runs exactly once, recursively. Lifetime accumulators (total_*andlifetime_stats_params) are preserved as before; if you emitted metrics from hooks that observed the intermediate double-reset state, re-verify them.- 3. Packaging: pyproject-only, Python 3.12–3.14.
setup.pyis gone; all metadata lives inpyproject.toml. Supported Pythons are 3.12 – 3.14.boto3remains the only mandatory runtime dependency, and the new optional extrasosw[durable]pulls the AWS Durable Execution SDK. Build tooling that patchedsetup.pymust targetpyproject.toml.- 4. ``import sosw`` is a lazy façade.
The package
__init__uses PEP 562 lazy attribute resolution:import soswno longer importsboto3or any submodule, and emits no warnings.from sosw import Processorstill works — names resolve on first access. Two consequences:import-time side effects are gone — anything that relied on
import soswtransitively importing submodules must import them explicitly (import sosw.app);sosw.__version__is now resolved lazily from the installed package metadata.
- 5. ``disable_ddb_config`` — the per-function config lookup can be switched off.
Set the class attribute
DISABLE_DDB_CONFIG = Trueon your Processor, or pass a truthydisable_ddb_configkey inDEFAULT_CONFIG/custom_config, to skip the{AWS_LAMBDA_FUNCTION_NAME}_configlookup in DynamoDB / SSM (Configuration; absorbed from PR #376).- 6. Config pagination no longer loops forever.
SecretsManagerandSSMConfigpagination helpers never advanced theNextTokeninside their retry loops: any first response carrying a token re-requested the same page indefinitely. Both now advance the token and accumulate every page. If you worked around this by keeping secrets or SSM parameters below one page, multi-page results now genuinely arrive.- 7. LambdaApi error semantics (for adopters of private forebears).
LambdaApi is new in this release. If you migrate from one of its private predecessors, note the hardened contract: authorization runs before routing (
401even for unknown paths), unknown route or method →404(no405), and onlyApiErrorsubclasses map to specific HTTP statuses — any other exception is logged server-side and rendered as the generic500envelope{"error": {"code": "SERVER_ERROR", "message": "Internal server error"}}without leaking internals. Org-specific pieces (SQLAlchemy session stacks, hardcoded CORS origins and Cognito group names) were deliberately not ported — use the config parameters and thecheck_route_accesshook.
Also new in this release¶
LambdaApi — declarative router Processor for API Gateway.
Durable functions support —
get_durable_lambda_handler,durable_wait,parse_durable_result; extrasosw[durable].helpers.recursive_matches_extractgained thecase_insensitiveoption (contributed by @SHMaryana, #379).The
ApiErrorexception hierarchy insosw.components.exceptions(Exceptions).
Upgrade checklist¶
Grep your code for the removed entities (
Orchestrator,Scheduler,Scavenger,Worker,WorkerAssistant,Labourer,Essential,sosw.managers). Any hit → either pinpip install 'sosw<3'or migrate that function to the managed services above.pip install --upgrade sosw(or bump the version in your Layer / requirements) on Python 3.12+.Run your test suite. Check that nothing depends on the pre-3.0
test-flag inversion or the doublereset_stats()(behavior changes 1–2 above).If you import submodules through side effects of
import sosw, make the imports explicit.