Skip to content

PUBLISH inside Lua scripts is re-delivered when the script is auto-retried on OCC conflict #500

Description

@liunyl

Summary

PUBLISH delivers its message immediately at command execution time, not at transaction commit. A Lua script runs as one transaction and is transparently re-executed from the top on OCC conflicts (retry_on_occ_error, default true) — so a script that publishes and then conflicts re-publishes on every retry.

Details

  • src/redis_command.cpp:3668-3671: PublishCommand::Execute calls redis_impl->Publish(chan_, message_) directly — delivery is a side effect outside the transactional write set.
  • src/redis_service.cpp:143 + :2606/:2625: whole-script (and simple-command) auto-retry on OCC-conflict error codes.

So EVAL "redis.call('publish', ...); redis.call('incr', KEYS[1])" under contention delivers the message once per retry attempt (at-least-once with duplicates), while the data effects commit exactly once.

Impact

Subscribers observe duplicated messages whose multiplicity depends on contention — surprising for users treating scripts as atomic. Same applies to a PUBLISH queued in MULTI if the EXEC body is retried.

Suggested fix

Buffer publishes issued inside a transaction/script and flush them after successful commit (Redis semantics: effects of a script become visible atomically), or at minimum disable auto-retry for scripts that contain PUBLISH and surface the conflict to the client.


Found during the module-docs review (#492); see docs/04-scripting-pubsub-blocking.md Gotchas.

🤖 Found with Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions