feat(runtime): add idempotency key support to trigger()#6710
Conversation
|
There's a race condition with the placeholder. If trigger A is mid-execution and trigger B hits with the same key, B gets back How about dropping the placeholder entirely? Just don't write to the cache until execute() finishes. That way the cache only ever holds real execution_ids. Webhook retries are usually seconds to minutes apart, so two triggers hitting within milliseconds shouldn't really happen in practice. Also, this uses |
fe439b6 to
7067d48
Compare
|
Good catch — you're right, returning a pending placeholder breaks the contract since callers use the ID for tracking. I dropped the placeholder and the lock entirely. The cache only gets written after execute() returns, so it always holds a real execution_id. No separate lock needed either — without a placeholder there's nothing to protect atomically, and the dict operations between awaits run on the event loop without interleaving. The tradeoff is a tiny window where a concurrent trigger could slip through, but execute() is non-blocking (just creates a task and returns), so that window is microseconds — and webhook retries are seconds apart anyway. Pushed the update. |
|
Hey @Hundao — just checking in. I pushed the update dropping the placeholder and lock as discussed. Let me know if there's anything else you'd like changed. |
Fixes #5947
Adds an optional
idempotency_keyparam totrigger()andtrigger_and_wait(). If the same key comes in again within the TTL window (default 5 min), we return the cached execution_id instead of starting a new run. Cache uses OrderedDict with TTL expiry and FIFO eviction at 10k keys. Placeholders + async lock handle the race between concurrent retries.Backward compatible — defaults to None, existing callers unchanged.
20 tests added.