Skip to content

Async actions: unique() - #11

Merged
ogorzalka merged 1 commit into
mainfrom
feat/async-unique
Oct 7, 2026
Merged

ogorzalka merged 1 commit into
mainfrom
feat/async-unique

Conversation

@ogorzalka

Copy link
Copy Markdown
Member

Phase 2, step C: unique().

Action::add('save_post_event', SyncEventToCrm::class)->async()->unique();          // lock expires after a day
Action::add('save_post_event', SyncEventToCrm::class)->async()->unique(for: 3600);

Identical triggers (same hook, same handler, same normalized arguments) are merged while the first one has not started running.

The lock (UniqueLock)

  • An option pollora_unique_{sha1}, not autoloaded, holding its expiry time.
  • Taken atomically with add_option(): the unique key on option_name lets only one process create it. An expired lock is taken over the same way: delete, then add_option(), so of two processes only one wins.
  • Its own prefix, so the WP-Cron recovery query never scans locks.
  • Released when the first attempt starts, so a trigger arriving during execution queues again (design doc: "as long as the first one has not been executed").
  • A retry does not release it: it may belong to a newer trigger by then.
  • Released when queuing fails, before the in-place fallback.
  • Cannot be stored (database error, not a duplicate): treated as a queuing failure, so debug mode throws and production reports and runs in place. Never a silent merge that would lose work.
  • Expired locks are deleted by the daily maintenance task (pollora/async/recover), which taking a lock schedules.

Cost: one write at trigger time, plus one read when the lock exists, as the design doc states.

Tests

195 passed, 12 new: merging, autoload flag and expiry, release at first attempt, expired takeover, hook and handler told apart, retry versus newer lock, release on queuing failure, sync driver, storage failure, pruning, 1.2.0 payloads. The real-WordPress suite passes. PHPStan level 5 and Pint pass.

@ogorzalka
ogorzalka merged commit 634049b into main Oct 7, 2026
5 checks passed
@ogorzalka
ogorzalka deleted the feat/async-unique branch October 7, 2026 13:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant