Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c66b448
feat: bus
cmilesio Feb 20, 2026
e7065b7
docs: readme
cmilesio Feb 20, 2026
b14dcd0
docs: examples
cmilesio Feb 20, 2026
4255816
chore: tests
cmilesio Feb 21, 2026
531137c
test: fix
cmilesio Feb 21, 2026
c109f89
fix: ci
cmilesio Feb 21, 2026
2933e6c
test: fix
cmilesio Feb 21, 2026
2e81dfd
fix: test
cmilesio Feb 21, 2026
776b711
chore: remove redundant integration run
cmilesio Feb 21, 2026
a6808e9
chore: test coverage
cmilesio Feb 21, 2026
be1b99a
docs: readme
cmilesio Feb 21, 2026
ffc45fa
docs: readme
cmilesio Feb 21, 2026
2ce895b
docs: readme
cmilesio Feb 21, 2026
7402a1b
docs: readme
cmilesio Feb 21, 2026
1225631
docs: readme
cmilesio Feb 21, 2026
4fdb83b
docs: readme
cmilesio Feb 21, 2026
078c385
docs: readme
cmilesio Feb 21, 2026
3f00fa9
docs: readme (skip ci)
cmilesio Feb 21, 2026
0b8e8ee
docs: readme (skip ci)
cmilesio Feb 21, 2026
918f647
docs: readme (skip ci)
cmilesio Feb 21, 2026
5527855
chore: test coverage
cmilesio Feb 21, 2026
31fda70
refactor: task -> job
cmilesio Feb 21, 2026
10e7eee
refactor: task -> job
cmilesio Feb 21, 2026
4e52a8e
refactor: task -> job
cmilesio Feb 21, 2026
e788ee0
refactor: task -> job
cmilesio Feb 21, 2026
6c3add1
refactor: task -> job
cmilesio Feb 21, 2026
02ddf15
docs: readme
cmilesio Feb 21, 2026
00e56eb
refactor: task -> job
cmilesio Feb 21, 2026
c6b38bc
fix: SQS republish ack safety and respect RabbitMQ job queue routing
cmilesio Feb 22, 2026
5a19063
chore: Harden RabbitMQ retry handling and recover stale DB processing…
cmilesio Feb 22, 2026
dec4541
feat(queue): add configurable recovery policy, republish failure even…
cmilesio Feb 22, 2026
36d29cb
test(integration): align sqs and rabbitmq scenario workers with per-s…
cmilesio Feb 22, 2026
bba0a81
test(integration): isolate sqs restart recovery scenario queue to avo…
cmilesio Feb 22, 2026
5bfd350
test(integration): add duration override precedence tests and shared …
cmilesio Feb 22, 2026
be61828
test(bus): align rabbitmq integration dispatch queue with worker defa…
cmilesio Feb 22, 2026
c1379ee
ci(soak): publish scenario duration summaries and artifacts
cmilesio Feb 22, 2026
e7826ea
docs(ga): define release-gate checklist with commands and evidence cr…
cmilesio Feb 22, 2026
0e26a65
test(integration): relax db poison-retry wait budget for transient CI…
cmilesio Feb 22, 2026
0663ed5
Update README.md
cmilesio Feb 22, 2026
dcc9556
fix: tests
cmilesio Feb 22, 2026
1daad2a
refactor: bus collapse into queue
cmilesio Feb 23, 2026
6fe57f8
docs: readme
cmilesio Feb 23, 2026
28a3005
docs: readme
cmilesio Feb 23, 2026
08a102e
docs: examples
cmilesio Feb 23, 2026
21ac4bd
chore: cleanup
cmilesio Feb 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/scripts/extract_scenario_durations.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
set -euo pipefail

if [[ $# -lt 2 ]]; then
echo "usage: $0 <log-file> <output-md>" >&2
exit 2
fi

log_file="$1"
out_file="$2"

mkdir -p "$(dirname "$out_file")"

{
echo "## Scenario Durations"
echo
echo "Source log: \`$(basename "$log_file")\`"
echo
} >"$out_file"

if [[ ! -f "$log_file" ]]; then
echo "_log file not found_" >>"$out_file"
exit 0
fi

matches="$(grep -Eo '\[[^]]+\]\[[^]]+\] duration=[^[:space:]]+' "$log_file" || true)"
if [[ -z "$matches" ]]; then
echo "_no scenario duration lines found_" >>"$out_file"
exit 0
fi

{
echo "| Backend | Scenario | Duration |"
echo "|---|---|---|"
while IFS= read -r line; do
backend="$(sed -E 's/^\[([^]]+)\]\[([^]]+)\] duration=([^[:space:]]+)$/\1/' <<<"$line")"
scenario="$(sed -E 's/^\[([^]]+)\]\[([^]]+)\] duration=([^[:space:]]+)$/\2/' <<<"$line")"
duration="$(sed -E 's/^\[([^]]+)\]\[([^]]+)\] duration=([^[:space:]]+)$/\3/' <<<"$line")"
printf '| %s | %s | `%s` |\n' "$backend" "$scenario" "$duration"
done <<<"$matches"
} >>"$out_file"
113 changes: 109 additions & 4 deletions .github/workflows/soak.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,60 @@ on:
workflow_dispatch:

jobs:
integration-evidence:
runs-on: ubuntu-latest
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
backend: [redis, mysql, postgres, sqlite, nats, sqs, rabbitmq]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "stable"

- name: Install dependencies
run: go mod download

- name: Run shared integration scenario matrix (evidence)
env:
RUN_INTEGRATION: "1"
INTEGRATION_BACKEND: ${{ matrix.backend }}
run: |
set -euo pipefail
mkdir -p .artifacts
go test -tags=integration ./... \
-run '^TestIntegrationScenarios_AllBackends$' \
-count=1 -v \
| tee ".artifacts/integration-scenarios-${{ matrix.backend }}.log"

- name: Summarize evidence durations
if: always()
run: |
.github/scripts/extract_scenario_durations.sh \
".artifacts/integration-scenarios-${{ matrix.backend }}.log" \
".artifacts/integration-scenarios-${{ matrix.backend }}-durations.md"
{
echo "### integration-evidence / ${{ matrix.backend }}"
cat ".artifacts/integration-scenarios-${{ matrix.backend }}-durations.md"
echo
} >> "$GITHUB_STEP_SUMMARY"

- name: Upload evidence logs
if: always()
uses: actions/upload-artifact@v4
with:
name: integration-evidence-${{ matrix.backend }}
path: .artifacts/*
if-no-files-found: warn

integration-soak:
runs-on: ubuntu-latest
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
Expand All @@ -22,17 +74,44 @@ jobs:
go-version: "stable"

- name: Install dependencies
run: go mod tidy
run: go mod download

- name: Run integration soak scenario suite
env:
RUN_INTEGRATION: "1"
RUN_SOAK: "1"
INTEGRATION_BACKEND: ${{ matrix.backend }}
run: go test -tags integration ./... -run '^TestIntegrationScenarios_AllBackends$'
run: |
set -euo pipefail
mkdir -p .artifacts
go test -tags=integration ./... \
-run '^TestIntegrationScenarios_AllBackends$' \
-count=1 -v \
| tee ".artifacts/integration-soak-${{ matrix.backend }}.log"

- name: Summarize soak durations
if: always()
run: |
.github/scripts/extract_scenario_durations.sh \
".artifacts/integration-soak-${{ matrix.backend }}.log" \
".artifacts/integration-soak-${{ matrix.backend }}-durations.md"
{
echo "### integration-soak / ${{ matrix.backend }}"
cat ".artifacts/integration-soak-${{ matrix.backend }}-durations.md"
echo
} >> "$GITHUB_STEP_SUMMARY"

- name: Upload soak logs
if: always()
uses: actions/upload-artifact@v4
with:
name: integration-soak-${{ matrix.backend }}
path: .artifacts/*
if-no-files-found: warn

integration-chaos:
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
Expand All @@ -47,10 +126,36 @@ jobs:
go-version: "stable"

- name: Install dependencies
run: go mod tidy
run: go mod download

- name: Run integration chaos scenario subset
env:
RUN_INTEGRATION: "1"
INTEGRATION_BACKEND: ${{ matrix.backend }}
run: go test -tags integration ./... -run "TestIntegrationScenarios_AllBackends/.*/scenario_(enqueue_during_broker_fault|consume_after_broker_recovery|shutdown_during_delay_retry|multi_worker_contention)$"
run: |
set -euo pipefail
mkdir -p .artifacts
go test -tags=integration ./... \
-run "TestIntegrationScenarios_AllBackends/.*/scenario_(enqueue_during_broker_fault|consume_after_broker_recovery|shutdown_during_delay_retry|multi_worker_contention)$" \
-count=1 -v \
| tee ".artifacts/integration-chaos-${{ matrix.backend }}.log"

- name: Summarize chaos durations
if: always()
run: |
.github/scripts/extract_scenario_durations.sh \
".artifacts/integration-chaos-${{ matrix.backend }}.log" \
".artifacts/integration-chaos-${{ matrix.backend }}-durations.md"
{
echo "### integration-chaos / ${{ matrix.backend }}"
cat ".artifacts/integration-chaos-${{ matrix.backend }}-durations.md"
echo
} >> "$GITHUB_STEP_SUMMARY"

- name: Upload chaos logs
if: always()
uses: actions/upload-artifact@v4
with:
name: integration-chaos-${{ matrix.backend }}
path: .artifacts/*
if-no-files-found: warn
31 changes: 3 additions & 28 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
set -euo pipefail
matrix_line="$(awk '/backend: \[/{print; exit}' .github/workflows/test.yml)"
test -n "$matrix_line"
for backend in redis mysql postgres sqlite nats sqs rabbitmq; do
for backend in null sync workerpool redis mysql postgres sqlite nats sqs rabbitmq; do
if ! echo "$matrix_line" | grep -Eq "(^|[^a-z])${backend}([^a-z]|$)"; then
echo "missing required integration backend in matrix: ${backend}"
exit 1
Expand Down Expand Up @@ -77,13 +77,13 @@ jobs:
- name: Run race tests
run: go test -race ./...

integration:
integration-all:
needs: [integration-matrix-guard, integration-scenarios-contract-guard]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
backend: [redis, mysql, postgres, sqlite, nats, sqs, rabbitmq]
backend: [null, sync, workerpool, redis, mysql, postgres, sqlite, nats, sqs, rabbitmq]
steps:
- name: Checkout
uses: actions/checkout@v4
Expand All @@ -101,28 +101,3 @@ jobs:
RUN_INTEGRATION: "1"
INTEGRATION_BACKEND: ${{ matrix.backend }}
run: go test -tags integration ./...

integration-scenarios:
needs: [integration-matrix-guard, integration-scenarios-contract-guard]
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
backend: [redis, mysql, postgres, sqlite, nats, sqs, rabbitmq]
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "stable"

- name: Install dependencies
run: go mod download

- name: Run integration scenario suite
env:
RUN_INTEGRATION: "1"
INTEGRATION_BACKEND: ${{ matrix.backend }}
run: go test -tags integration ./... -run '^TestIntegrationScenarios_AllBackends$'
14 changes: 7 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ CI matrix
- Ensure the integration backend matrix in `.github/workflows/test.yml` includes the backend.
- The `integration-matrix-guard` job enforces required backend entries.
- Nightly/manual soak scenario runs are defined in `.github/workflows/soak.yml` with `RUN_SOAK=1`.
- Duration guardrail env overrides for integration scenarios are documented in `docs/integration-scenarios.md` (`SCENARIO_DURATION_LIMIT_SECONDS*` with scenario/backend-specific precedence).

## Integration scenarios

Expand Down Expand Up @@ -52,11 +53,11 @@ Optional long-run scenario (enabled with `RUN_SOAK=1`):

What these prove:
- Worker lifecycle idempotency (`StartWorkers` and `Shutdown` can be called twice safely).
- Concurrent dispatch pressure with mixed task options (`Delay`, `Timeout`, `Retry`, `Backoff` where supported).
- Payload decode path via `Task.Bind(...)`.
- Poison task behavior by backend capability (retry ceiling where supported) and healthy-task recovery.
- Concurrent dispatch pressure with mixed job options (`Delay`, `Timeout`, `Retry`, `Backoff` where supported).
- Payload decode path via `Job.Bind(...)`.
- Poison job behavior by backend capability (retry ceiling where supported) and healthy-job recovery.
- Restart recovery only for backends that support deterministic restart durability in integration.
- Invalid JSON payload behavior through `Task.Bind(...)` does not wedge workers; valid payloads still process.
- Invalid JSON payload behavior through `Job.Bind(...)` does not wedge workers; valid payloads still process.
- Uniqueness is enforced per queue (duplicate rejected in same queue, allowed across queues).
- Dispatch context cancellation behavior is verified per backend capability, with healthy follow-up processing.
- Worker shutdown during delayed/retry workloads is exercised with restart and recovery assertions where supported.
Expand All @@ -66,6 +67,5 @@ What these prove:
- FIFO ordering contract is asserted for backends marked ordering-capable.
- Backpressure saturation scenarios prove continued forward progress.
- Large payload processing is validated end-to-end.
- Config/task-option fuzz coverage validates mixed option combinations across backends for stability.
- End-to-end completion for all successfully dispatched tasks.

- Config/job-option fuzz coverage validates mixed option combinations across backends for stability.
- End-to-end completion for all successfully dispatched jobs.
Loading