celery-sqs-native-delay ⏳️
celery[sqs] fetches every ETA/countdown task off the queue immediately and
holds it, unacked, in the worker's own memory until the ETA arrives. SQS
already has a native mechanism for this. This package makes Celery use it
by wrapping kombu's existing SQS transport.
How it routes
flowchart LR
A["task published<br/>with a delay"] --> B{".fifo queue?"}
B -->|yes| C["celery's own<br/>ETA timer"]
B -->|no| D{"delay ≤ 900s?"}
D -->|yes| E["SQS native<br/>DelaySeconds"]
D -->|no| F["EventBridge Scheduler<br/>one-time schedule"]
| Delay | Handled by |
|---|---|
at or below 900s |
SQS native DelaySeconds |
above 900s |
an EventBridge Scheduler one-time schedule |
any delay on a .fifo queue |
left alone, celery's own ETA timer |
Install and configure
pip install celery-sqs-native-delay
app = Celery(
"myapp",
broker="sqs://",
broker_transport="celery_sqs_native_delay:Transport",
broker_transport_options={
"eventbridge_role_arn": "arn:aws:iam::123456789012:role/celery-scheduler",
},
)
broker_transport_options key |
Required | Meaning |
|---|---|---|
eventbridge_role_arn |
yes | role EventBridge Scheduler assumes to call SendMessage |
eventbridge_dead_letter_arn |
no, but recommended | DeadLetterConfig on every schedule |
eventbridge_retry_policy |
no | RetryPolicy on every schedule |
eventbridge_group_name |
no | schedule group |
Requirements and limitations
- Celery protocol 2 is required. Protocol 2 has been celery's default
since
4.0(2016), so almost every app already meets this. Protocol 2 putsetain the message headers. Protocol 1 puts it in the body, which this package never inspects, so a protocol 1 delay is invisible from here and falls back silently to celery's own local timer. - FIFO queues get no native delay.
SQShas no per-messageDelaySecondson a.fifoqueue, andEventBridgeScheduler can't be used either, since separate schedule invocations have no ordering guarantee relative to each other. A delayed publish to a.fifoqueue falls back entirely to celery's own localETAtimer, exactly as if this package weren't installed.- The way to get delay on a
FIFOqueue without any of that is a queue-levelDelaySecondsattribute set at queue creation. It applies uniformly to every message and preserves ordering.
- The way to get delay on a
IAM
Three things need permissions: the role in eventbridge_role_arn, that
role again for delivery, and the publisher itself.
1. The role trusts EventBridge Scheduler to assume it:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "scheduler.amazonaws.com" },
"Action": "sts:AssumeRole",
"Condition": {
"StringEquals": { "aws:SourceAccount": "123456789012" },
"ArnLike": {
"aws:SourceArn": "arn:aws:scheduler:us-east-1:123456789012:schedule/*/*"
}
}
}
]
}
2. The role can deliver to your queue(s):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sqs:SendMessage",
"Resource": "arn:aws:sqs:us-east-1:123456789012:myqueue"
}
]
}
3. The publisher can create schedules and pass the role to EventBridge:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["scheduler:CreateSchedule", "sqs:GetQueueAttributes"],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::123456789012:role/celery-scheduler"
}
]
}
Failure and recovery
A CreateSchedule failure (throttling, a missing role, etc) raises
out of Channel._put, which propagates up through producer.publish, so
celery's own task_publish_retry covers it with no extra handling needed
from this package.
A schedule that fires but cannot deliver, for instance a deleted queue, a
revoked role permission, or a KMS error on an encrypted queue, goes to
eventbridge_dead_letter_arn if you set one. Setting it is recommended:
without it, a schedule that fails to deliver leaves nothing behind, because
ActionAfterCompletion='DELETE' removes the schedule once it has run.
Retries
Celery reuses one task id across every retry, but "The rule" above is
applied fresh on each publish. A retry with a growing backoff can start
under 900s on native DelaySeconds, then move to EventBridge Scheduler
once a later retry's countdown passes 900s, with no special handling on
your part:
@app.task(bind=True, max_retries=5)
def my_task(self):
try:
...
except Exception as exc:
countdown = 300 * (2**self.request.retries)
raise self.retry(exc=exc, countdown=countdown)
Quotas
Every delay above 900s costs one EventBridge Scheduler CreateSchedule
call and one invocation. Check your account's EventBridge Scheduler quotas
(schedule count, CreateSchedule rate, invocation rate) against your
expected volume before relying on this path at scale.
Development
make install # uv sync --dev
make test # unit tests, no broker needed
make up # start a local ministack (https://ministack.org)
make test-integration # integration tests against that ministack
make test-all # integration + unit tests
make down
make lint
License
MIT, see LICENSE.
Metadata
Release files for celery-sqs-native-delay 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| celery_sqs_native_delay-0.1.0.tar.gz | 54.4 kB | Without provenance | Details for celery_sqs_native_delay-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| celery_sqs_native_delay-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for celery_sqs_native_delay-0.1.0-py3-none-any.whl |
Total release size: 62.6 kB
Release files / celery_sqs_native_delay-0.1.0.tar.gz
| Download URL | celery_sqs_native_delay-0.1.0.tar.gz |
|---|---|
| Size | 54.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d37db3a8e691dc7e2725bbb56345e9f963898a8ada81b2a9ab3d40e1b946baf6
|
|
BLAKE2b-256 checksum How to use checksums |
bf72fb1176066c14b280bc174032fa9b4e7b39409fe0b17e5a6509ea604c778b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / celery_sqs_native_delay-0.1.0-py3-none-any.whl
| Download URL | celery_sqs_native_delay-0.1.0-py3-none-any.whl |
|---|---|
| Size | 8.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d53ca72ae8084f208e261602c9047fdfd85bbe64281a4486a96149c1ad6d38f2
|
|
BLAKE2b-256 checksum How to use checksums |
c42240955f8b1bfa7000b7f0f76a08b7b3f6166b829e75ad24008baf3060d81d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.0 {"installer":{"name":"uv","version":"0.12.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Security for celery-sqs-native-delay 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.