[GH-ISSUE #568] [FEATURE REQUEST] Update Task #1284

Open
opened 2026-03-07 22:08:16 +03:00 by kerem · 5 comments
Owner

Originally created by @endrawanandika on GitHub (Nov 2, 2022).
Original GitHub issue: https://github.com/hibiken/asynq/issues/568

Originally assigned to: @hibiken on GitHub.

Is your feature request related to a problem? Please describe.
I have enqueued delayed task

info, err := client.Enqueue(task, asynq.ProcessAt(firstTime), asynq.TaskID(taskID))

But after some time, I want to update the time for that task to be processed (can be earlier or later). The Task that is created have task id (or I can get from info.ID), so I want to be able to update it in the future.

I can do delete task and enqueue again,

err := inspector.DeleteTask(queueName, taskID)
if err != nil {
    return err
}
info, err := client.Enqueue(task, asynq.ProcessAt(secondTime), asynq.TaskID(taskID))
if err != nil {
    return err
}

but if somehow I can't enqueue after delete task, the task will be lost. This will be a trouble if there are checking if task exist before update, so retrying doesn't work.

_, err := inspector.GetTaskInfo(queueName, taskID)
if err != nil {
    if err.Error() == fmt.Sprintf("asynq: %s", asynq.ErrTaskNotFound) {
        // task doesn't exist, so doesn't need to update
        return nil
    }
    return err
}
err = inspector.DeleteTask(queueName, taskID)
if err != nil {
    return err
}
info, err := client.Enqueue(task, asynq.ProcessAt(secondTime), asynq.TaskID(taskID))
if err != nil {
    return err
}

Another approach that I can think of is create task UpdateTask, that will do:

err := inspector.DeleteTask(queueName, taskID)
if err != nil && err.Error() != fmt.Sprintf("asynq: %s", asynq.ErrTaskNotFound) { // if task is not found, it can be because retrying delete again
    return err
}
info, err := client.Enqueue(task, asynq.ProcessAt(secondTime), asynq.TaskID(taskID))
if err != nil {
    return err
}

with enqueue UpdateTask like this:

taskInfo, err := r.inspector.GetTaskInfo(queueName, taskID)
if err != nil {
    return err
}
info, err := client.Enqueue(asynq.NewTask(UPDATE_TASK_TYPE, taskInfo.Payload), asynq.ProcessAt(secondTime), asynq.TaskID(taskID))
if err != nil {
    return err
}

So the retrying just need to be retried from Delete, not checking if task exist.

Beside that, I can also save task payload somewhere else so I can refer it.

I think the library should be able to do atomic update.

Let me know if there are missing docs that I haven't read to fulfill my requirements.

Describe the solution you'd like

info, err := client.UpdateTask(task, asynq.ProcessAt(firstTime), asynq.TaskID(taskID))
if err != nil {
    if err == asynq.ErrTaskNotFound {
        // can do something else if task doesn't exist at the first place
        return nil
    }
    return err
}

It can also return err if the task isn't exist, so I know that it's updated or not (I don't want enqueue non existant task).

Describe alternatives you've considered

  • Have option like asynq.UpdateIfExist(true).
  • Using transaction and pipeline so DeleteTask and Enqueue can be 1 atomic operation.
  • Support workflow that can handle this problem.

Additional context

Originally created by @endrawanandika on GitHub (Nov 2, 2022). Original GitHub issue: https://github.com/hibiken/asynq/issues/568 Originally assigned to: @hibiken on GitHub. **Is your feature request related to a problem? Please describe.** I have enqueued delayed task ```go info, err := client.Enqueue(task, asynq.ProcessAt(firstTime), asynq.TaskID(taskID)) ``` But after some time, I want to update the time for that task to be processed (can be earlier or later). The Task that is created have task id (or I can get from `info.ID`), so I want to be able to update it in the future. I can do delete task and enqueue again, ```go err := inspector.DeleteTask(queueName, taskID) if err != nil { return err } info, err := client.Enqueue(task, asynq.ProcessAt(secondTime), asynq.TaskID(taskID)) if err != nil { return err } ``` but if somehow I can't enqueue after delete task, the task will be lost. This will be a trouble if there are checking if task exist before update, so retrying doesn't work. ```go _, err := inspector.GetTaskInfo(queueName, taskID) if err != nil { if err.Error() == fmt.Sprintf("asynq: %s", asynq.ErrTaskNotFound) { // task doesn't exist, so doesn't need to update return nil } return err } err = inspector.DeleteTask(queueName, taskID) if err != nil { return err } info, err := client.Enqueue(task, asynq.ProcessAt(secondTime), asynq.TaskID(taskID)) if err != nil { return err } ``` Another approach that I can think of is create task `UpdateTask`, that will do: ```go err := inspector.DeleteTask(queueName, taskID) if err != nil && err.Error() != fmt.Sprintf("asynq: %s", asynq.ErrTaskNotFound) { // if task is not found, it can be because retrying delete again return err } info, err := client.Enqueue(task, asynq.ProcessAt(secondTime), asynq.TaskID(taskID)) if err != nil { return err } ``` with enqueue `UpdateTask` like this: ```go taskInfo, err := r.inspector.GetTaskInfo(queueName, taskID) if err != nil { return err } info, err := client.Enqueue(asynq.NewTask(UPDATE_TASK_TYPE, taskInfo.Payload), asynq.ProcessAt(secondTime), asynq.TaskID(taskID)) if err != nil { return err } ``` So the retrying just need to be retried from Delete, not checking if task exist. Beside that, I can also save task payload somewhere else so I can refer it. I think the library should be able to do atomic update. Let me know if there are missing docs that I haven't read to fulfill my requirements. **Describe the solution you'd like** ```go info, err := client.UpdateTask(task, asynq.ProcessAt(firstTime), asynq.TaskID(taskID)) if err != nil { if err == asynq.ErrTaskNotFound { // can do something else if task doesn't exist at the first place return nil } return err } ``` It can also return err if the task isn't exist, so I know that it's updated or not (I don't want enqueue non existant task). **Describe alternatives you've considered** - Have option like `asynq.UpdateIfExist(true)`. - Using transaction and pipeline so `DeleteTask` and `Enqueue` can be 1 atomic operation. - Support workflow that can handle this problem. **Additional context**
Author
Owner

@184104489 commented on GitHub (Jan 4, 2023):

@hibiken Any news? I long for this feature. Thanks for your work

<!-- gh-comment-id:1370442277 --> @184104489 commented on GitHub (Jan 4, 2023): @hibiken Any news? I long for this feature. Thanks for your work
Author
Owner

@marcown commented on GitHub (Jan 4, 2023):

@hibiken I would also be interested. Do you need any help or could you sketch your idea how you would do it? It would also be useful for me not only to update a delayed task but also to update the payload of a running task

<!-- gh-comment-id:1370745876 --> @marcown commented on GitHub (Jan 4, 2023): @hibiken I would also be interested. Do you need any help or could you sketch your idea how you would do it? It would also be useful for me not only to update a delayed task but also to update the payload of a running task
Author
Owner

@ray2011 commented on GitHub (Apr 11, 2023):

This is a useful feature.

<!-- gh-comment-id:1502633458 --> @ray2011 commented on GitHub (Apr 11, 2023): This is a useful feature.
Author
Owner

@dedisuryadi commented on GitHub (Jul 8, 2023):

Having the ability to edit the payload would also be nice

<!-- gh-comment-id:1627275948 --> @dedisuryadi commented on GitHub (Jul 8, 2023): Having the ability to edit the payload would also be nice
Author
Owner

@aziz-the-dev commented on GitHub (Mar 17, 2025):

Hi, I'm working on task payload update functionality. For now, only scheduled tasks can be updated with my implementation of the update task. Haven't tested it properly; also, I'm new to this library, so it's possible for me to miss some internal logic.
I used Inspector.DeleteTask is the starting point for this. It would be nice if someone with more experience could guide me with the internal structure of the library.

<!-- gh-comment-id:2728390478 --> @aziz-the-dev commented on GitHub (Mar 17, 2025): Hi, I'm working on task payload update functionality. For now, only scheduled tasks can be updated with my implementation of the update task. Haven't tested it properly; also, I'm new to this library, so it's possible for me to miss some internal logic. I used Inspector.DeleteTask is the starting point for this. It would be nice if someone with more experience could guide me with the internal structure of the library.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/asynq#1284
No description provided.