Request lifecycle
Cold start
On the first request a new Lambda execution environment imports lambda_handlers:
-
configis imported, whose first line importssecrets_loader. IfAPP_SECRET_IDis set andAWS_SECRETS_MANAGERis not"False", the JSON secret is fetched and each key is copied intoos.environwithsetdefault(an explicit environment variable wins). -
run.pycallscreate_app("config"): flask-restx namespaces and blueprints are registered underBASE_PREFIX. -
Importing
pyb_flask_utils.authloads the sharedcommon/crmsecret (instance-id tokens and, if not already in the environment,AUTH_JWT_RSA_PUBLIC_KEY). -
setup_sentry()initialises Sentry outsidedev/local/test.
A cold start therefore costs two GetSecretValue calls. Warm invocations reuse everything.
Paths and stages
API Gateway passes the full request path to Lambda in event["path"], and apig-wsgi uses it as
PATH_INFO:
| Request | event["path"] |
Matches |
|---|---|---|
|
|
|
|
|
same |
|
|
|
The stage name is never part of event["path"]; the custom-domain base path is. That is why
production keeps BASE_PREFIX = "/actionstools" (config.py).
Request
-
CORS preflight.
OPTIONSis answered by API Gateway (mock integration from theCorsblock intemplate.yaml), never reaching Lambda. -
Routing.
/{proxy+}→ApiFunction→apig_wsgi→ Flask. -
Authentication. Every resource uses one of the decorators from
pyb_flask_utils.auth— see api/index.adoc#authentication. On success the view receiveslogin_id(email) andlogin_key(user uuid). -
Header context.
Helper(HEADERS).parse_headersmapsX-Actions-*and instance headers totarget_uuid,target_type,owner_uuid,instance_id(config.HEADERS). -
Service call. The view calls a service in the same package, which reads or writes DynamoDB and, for owner-only fields, asks the Payability internal API whether the user is the owner or a
CRM_ADMINsuper user. -
Response.
prepare_json_responsewraps everything in the{data, meta, status_code}envelope. Exceptions are converted byhandle_errors/PybApi.handle_error.
Side effects
Anything slow or best-effort is queued with @async_task:
| Trigger | Async task |
|---|---|
Task created (sync mode) |
|
Task created with |
|
Task updated by a logged-in user |
|
Comment on a task |
|
Each Slack DM |
|
First request for an unknown counter |
|
The API returns as soon as the lambda:Invoke (type Event) is accepted. See
Worker Lambda & async tasks for what happens next and how failures surface.