feat(smartacme): Integrate @push.rocks/taskbuffer TaskManager to coordinate ACME certificate issuance with per-domain mutex, global concurrency cap, and account-level rate limiting; refactor issuance flow into a single reusable cert-issuance task, expose issuance events, and update lifecycle to start/stop the TaskManager. Add configuration for concurrent issuances and sliding-window order limits, export taskbuffer types/plugins, and update tests and docs accordingly.

This commit is contained in:
2026-02-15 22:22:12 +00:00
parent 68178366d5
commit cfc0695c8a
9 changed files with 257 additions and 89 deletions

View File

@@ -28,6 +28,21 @@ Key files:
Usage in `ts/plugins.ts`: `import * as acme from './acme/index.js'` (replaces `acme-client`)
## Concurrency & Rate Limiting (taskbuffer integration)
As of v9.1.0, `@push.rocks/lik.InterestMap` was replaced with `@push.rocks/taskbuffer.TaskManager` for coordinating concurrent certificate requests. This provides:
- **Per-domain mutex** (`cert-domain-mutex`): Only one ACME issuance per TLD at a time, with `resultSharingMode: 'share-latest'` so queued callers get the same result without re-issuing.
- **Global concurrency cap** (`acme-global-concurrency`): Limits total parallel ACME operations (default 5, configurable via `maxConcurrentIssuances`).
- **Account-level rate limiting** (`acme-account-rate-limit`): Sliding-window rate limit (default 250 orders per 3 hours, configurable via `maxOrdersPerWindow`/`orderWindowMs`) to stay under Let's Encrypt limits.
- **Step-based progress**: The cert issuance task uses `notifyStep()` for prepare/authorize/finalize/store phases, observable via `smartAcme.certIssuanceEvents`.
Key implementation details:
- A single reusable `Task` named `cert-issuance` handles all domains via `triggerTaskConstrained()` with different inputs.
- The `shouldExecute` callback on the domain mutex checks the certmanager cache as a safety net.
- `TaskManager.start()` is called in `SmartAcme.start()` and `TaskManager.stop()` in `SmartAcme.stop()`.
- The "no cronjobs specified" log messages during tests come from taskbuffer's internal CronManager polling — harmless noise when no cron tasks are scheduled.
## Dependency Notes
- `acme-client` was replaced with custom implementation in `ts/acme/` + `@peculiar/x509` for CSR generation