Repository navigation
Conversation
Make the adapter options of the publisher, rate limit, and lock helpers
follow the same units and shapes:
- Publisher `resume.seconds` is now `resume.ttl`, in milliseconds like
every lock and rate limit timing. `DurablePublisherObject`'s
`cleanupIntervalSeconds` is now `cleanupInterval`, also in
milliseconds. Redis-backed publishers set the stream expiry with
`PEXPIRE`.
- Rate limiters take a flat `timeout` (default 0, no waiting) like the
lock, replacing `blockingUntilReady: { enabled, timeout }`.
- `UpstashRateLimiter` now takes an Upstash `Redis` client like
`UpstashPublisher` and `UpstashLocker`. It extends
`BaseRedisRateLimiter`, so it shares counters with `RedisRateLimiter`
and `BunRedisRateLimiter`. The `@upstash/ratelimit` peer dependency
and the `waitUntil` option are gone.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G38QumhkQEV68MTzxy2oQd
- Move the wait-until-reset loop and weight validation shared by `MemoryRateLimiter` and `BaseRedisRateLimiter` into one internal module, dropping the leftover `timeoutMs` parameter. - Share one exported `PublisherResumeOptions` type between the memory and Redis publishers, and extend it in `DurablePublisherObject`. - Say that the rate limiter gives up, rather than rejects, when the window will not reset before the timeout, since `limit` returns a failed result. - Drop an unused `UpstashPublisher` instance from the compatibility test and a stale comment from the Upstash rate limiter test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G38QumhkQEV68MTzxy2oQd
…s-inconsistencies-cak51z Keep the renamed `ttl`, `timeout`, `cleanupInterval` and shared `resume` options, declared as `X | undefined` to follow #2278. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G38QumhkQEV68MTzxy2oQd
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
More templates
@orpc/ai-sdk
@orpc/arktype
@orpc/bun
@orpc/client
@orpc/cloudflare
@orpc/contract
@orpc/experimental-effect
@orpc/evlog
@orpc/hibernation
@orpc/json-schema
@orpc/experimental-lock
@orpc/mcp
@orpc/msw
@orpc/nest
@orpc/next
@orpc/node
@orpc/openapi
@orpc/opentelemetry
@orpc/pinia-colada
@orpc/pino
@orpc/publisher
@orpc/ratelimit
@orpc/server
@orpc/shared
@orpc/swr
@orpc/tanstack-query
@orpc/trpc
@orpc/valibot
@orpc/zod
commit: |
Merging this PR will not alter performance1 warning
Comparing Footnotes
|
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Publisher resume retention moves to milliseconds —
resume.seconds→resume.ttl(default300000) behind a sharedPublisherResumeOptionstype, applied to memory, Redis/Upstash/Bun Redis (viaBaseRedisPublisher) and the Cloudflare Durable Object, which also renamescleanupIntervalSeconds→cleanupInterval(ms). - Redis stream expiry uses
PEXPIRE— the publish script and its trim/TTL arguments now derive fromresumeTtlms instead of seconds. - Rate-limiter blocking flattened to
timeout—blockingUntilReady: { enabled, timeout }→ flattimeout(default0) across memory, Redis, Upstash and Bun Redis, backed by the sharedblockUntilReady/resolveWeighthelpers inpackages/ratelimit/src/utils.ts. UpstashRateLimiterreworked — now extendsBaseRedisRateLimiterover an@upstash/redisclient with a fixed window and shares counters withRedisRateLimiter; drops@upstash/ratelimitandwaitUntil.- Docs and tests — publisher, rate-limit and v1 migration pages updated; adapter tests moved to the new options.
The Durable Object correctly keeps stored_at in seconds and converts ttl at cleanup (this.ttl / 1000), so existing tables are not invalidated. UpstashRateLimiter's evalScript follows the same redis.eval(script, keys, args) contract already used by UpstashLocker and UpstashPublisher. I found no stale seconds/blockingUntilReady/cleanupIntervalSeconds references outside the v1 migration guide, where they are intentional.
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏
Deploying with
|


Summary
The publisher, rate limit and lock adapters used different units and shapes for similar options. This PR fixes three inconsistencies:
resume.secondswas in seconds, while every lock and rate-limit timing is in milliseconds.timeouton the lock butblockingUntilReady: { enabled, timeout }on the rate limiter.UpstashRateLimitertook an@upstash/ratelimitinstance, whileUpstashPublisherandUpstashLockertake aRedisclient.Breaking changes
Publisher retention is in milliseconds
resume.secondsis nowresume.ttl, in milliseconds (default300000). This applies toMemoryPublisher,RedisPublisher,UpstashPublisherandBunRedisPublisher.DurablePublisherObject(@orpc/cloudflare) changed the same way:secondsis nowttl, andcleanupIntervalSecondsis nowcleanupInterval, both in milliseconds.Rate limiters take a flat
timeoutblockingUntilReady: { enabled, timeout }is nowtimeout, matching the lock. The default is0(don't wait), so default behavior is unchanged. This applies toMemoryRateLimiter,RedisRateLimiter,UpstashRateLimiterandBunRedisRateLimiter.As before, a request gives up right away when its window will not reset before the timeout.
UpstashRateLimitertakes aRedisclientUpstashRateLimiternow extendsBaseRedisRateLimiter, likeRedisRateLimiterandBunRedisRateLimiter, and shares counters with them.@upstash/ratelimitpeer dependency (@upstash/redisreplaces it) and thewaitUntiloption.Ratelimitinstance in a small customRateLimiter.Other changes
packages/ratelimit/src/utils.ts).resumetype: publishers share one exportedPublisherResumeOptionstype, whichDurablePublisherObjectResumeOptionsextends.PEXPIRE(ms) instead ofEXPIRE(s).stored_atcolumn stays in seconds, and the code convertsttlat cleanup. Existing tables keep their old column default, so switching the column to milliseconds would delete every stored event.| undefinedconvention: new optional fields are declared asX | undefined, following fix: accept explicitundefinedon optional option fields #2278.resumeRetentionSeconds/retentionSecondstottl,blockingUntilReadytotimeout, and shows a before/after for the Upstash rate limiter.Verification
pnpm lint,pnpm type:checkandpnpm docs:validatepass.PEXPIRE.bun testinpackages/bunpasses against local Redis (136 pass, 6 skip). The Cloudflare workerd tests pass (74).Redisclient. Separately, I ranUpstashRateLimiteragainst local Redis through a stand-in for the Upstash client'seval. It shared counters withRedisRateLimiterand waited and gave up as expected. That does not cover a real Upstash server.Generated by Claude Code
Note
Align publisher resume and rate-limit adapter options with the lock
PublisherResumeOptionswith millisecondttl; Redis, Upstash, memory, and Cloudflare Durable Object adapters now use it instead of seconds-based settings.blockingUntilReadyrate-limit option with a flat millisecondtimeout, backed by sharedblockUntilReadyandresolveWeightutilities in utils.ts.UpstashRateLimiteras aBaseRedisRateLimitersubclass that takes an@upstash/redisclient and runs the shared fixed-window Lua script, dropping the@upstash/ratelimitdependency andwaitUntil.resume.seconds→resume.ttl,cleanupIntervalSeconds→cleanupInterval,blockingUntilReady→timeout; Redis expiry now usesPEXPIREwith millisecond TTLs in base-redis.ts.🖇️ Linked Issues
Resolves algolia#3613 and fixes algolia#3511.
Macroscope summarized bb40f3a.