Skip to content

When RqueueMessageEnqueuer::enqueueUnique() is going to be properly implemented? #259

Description

@Tsar

Is your feature request related to a problem? Please describe.

I tried replacing db-scheduler with Rqueue in my project, because it fills the queue with a lot of tasks (a few million), db-scheduler has bottleneck on DB table single-row operations performance.
It looked really promising, I practically finished the implementation. But as soon as I started testing, I realized, that RqueueMessageEnqueuer::enqueueUnique() is not properly implemented. There are some TODOs in the code of the library.
I can't have same item processed in parallel, that's why I need to guarantee uniqueness of the item in the queue.

Describe the solution you'd like

I'd like RqueueMessageEnqueuer::enqueueUnique() to return false and not append anything to the queue in case item with same id is currently processed or pending or scheduled.

Describe alternatives you've considered

I've seen message deduplication guide.
But it looks like it's for solving another problem:

This does not handle the following cases

  • Multiple similar messages enqueue at the same time.
  • Multiple similar messages are trying to run at the same time.
  • Enqueuing new message when the existing one is running.
  • Enqueuing new message when the older message was discarded.

Activity

  1. sonus21 commented on Jul 15, 2025

    @sonus21
    Owner

    @Tsar thanks for flagging this! We can now implement enqueue deduplication since we have a message metadata store in place. The issue only occurs during the enqueue flow, and we can add a check before sending the message to the queue. It should be a small change, I’ll take a look soon. If you’re up for it, feel free to send a PR. The update would primarily involve adding a duplicate check in RqueueMessageEnqueuerImpl.

  2. Tsar commented on Jul 16, 2025

    @Tsar
    Author

    @sonus21 Thanks a lot for such a fast reaction!!

  3. sonus21 commented on Jul 22, 2025

    @sonus21
    Owner

    Can you test this with 3.4.0

  4. Tsar commented on Jul 22, 2025

    @Tsar
    Author

    Hi @sonus21,

    Thanks!
    I tried the new version. Now it looks like there's another problem: enqueueUnique() returns false when I try to enqueue the task with the same id as completed task.

    Here's how my test looks like:

    1. I have a task which sleeps for 100ms.
    2. I call enqueueUnique() for it twice with messageId = "unique-task".
    3. First attempt should return true, second should return false. This works now.
    4. Then the test waits until the task is completed and tries to call enqueueUnique() again. It returns false. I would expect true.
  5. sonus21 commented on Jul 23, 2025

    @sonus21
    Owner

    That’s the expected behavior, enqueueUnique is designed to prevent enqueuing tasks that have already been completed. Your expectation doesn’t align with how uniqueness is enforced.

    If you need different behavior, you’ll have to implement a custom workaround. One known approach is to perform your own uniqueness check using rqueueMessageMetadataService.getByMessageId("queue", "messageId") and inspect the message status accordingly. You can also use Redis based locking to prevent parallel enqueues.

    In such scenarios, if you intend to enqueue the same message ID again, you should ensure that the corresponding MessageMetadata and any related state (such as job state) are properly deleted beforehand.

  6. Tsar commented on Jul 24, 2025

    @Tsar
    Author

    So do you actually store unique completed tasks forever?

  7. sonus21 commented on Jul 24, 2025

    @sonus21
    Owner

    All tasks are stored in Redis, technically it can be stored forever but it has default ttl of 30 minutes (post execution).

  8. Tsar commented on Jul 25, 2025

    @Tsar
    Author

    Is this a configurable setting?
    It looks like if I set 0 (meaning completed tasks are immediately removed from Redis), then enqueueUnique() would work like I need it to.

  9. sonus21 commented on Jul 25, 2025

    @sonus21
    Owner

    yes, you can set that to zero or -1 it will delete immediately.

    rqueue.message.durability.in-terminal-state=0
    rqueue.job.durability.in-terminal-state=0
    
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions