Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rest Design for a task queue

Tags:

rest

I'm designing a task queue rest interface and wondering about a best practice.

One action is to accept the "next" task in the queue.

By accepting the job only the first worker will get the job.

The worker won't know the task or the task id until accepting the job.

Now I'm thinking I can't use a GET because it's not idempotent. If calling nextTask two times you get two different jobs. So I guess it should be a POST.

POST //rest/taskqueue?action=acceptTask

Or am I looking at it the wrong way?

like image 255
Fredrik L Avatar asked Jan 12 '13 00:01

Fredrik L


2 Answers

Basically:

  • GET - Reads data without modifying a resource (idempotent). You can do as many GETs as you want, it will never modify the resource.
  • PUT - Puts data explicitly in a resource (not idempotent)
  • POST - Appends data in a resource (not idempotent)
  • DELETE - Removes data from a resource (not idempotent)

This is how I would do it.

Enqueue a new task:

--> POST http://api.crazyjoes.com/v1/tasks/
--> {"data":{"lulcat":true}}
<-- 202 Accepted

Enqueue a new task with a specific ID:

--> PUT http://api.crazyjoes.com/v1/tasks/393ee7f6-c44a-4b34-86ac-92c9f31a4bc6/
--> {"data":{"lulcat":true}}
<-- 202 Accepted

Retrieve the oldest task:

--> GET http://api.crazyjoes.com/v1/tasks/oldest/
<-- 200 OK
<-- {"id":123,"data":{"lulcat":true}}

If the queue is empty:

--> GET http://api.crazyjoes.com/v1/tasks/oldest/
<-- 204 No Content

Dequeue a specific task:

--> DELETE http://api.crazyjoes.com/v1/tasks/123/
<-- 200 OK
<-- {"id":123,"data":{"lulcat":true}}

If the task has already been handled...

--> DELETE http://api.crazyjoes.com/v1/tasks/123/
<-- 410 Gone

If you want to dequeue the oldest item directly...

--> DELETE http://api.crazyjoes.com/v1/tasks/oldest/
<-- 200 OK
<-- {"id":123,"data":{"lulcat":true}}
like image 151
Robin Orheden Avatar answered Nov 14 '22 22:11

Robin Orheden


How about:

/tasks and /tasks/{taskId} are the usual collection of all tasks and an individual task, respectively.

/tasksqueue is the tasks on the queue, while /tasksqueue/top is the top of the queue, and only supports a GET. Let's assume that all tasks have a unique id.

Then issue GET /tasksqueue/top to get the id of the task at the top of the queue, and issue a DELETE /tasksqueue/{taskId} to attempt to pop it off the queue.

If it fails, i.e. returns a non-20x, it means someone else popped the queue between your calls.

If it succeeds, it will return the task in its body and you can do what you want with it, knowing you've successfully popped it. Or since you know its id, you can get the task info from /tasks/{taskId}.

It shouldn't succeed more than once.

And you can issue DELETE /tasksqueue/{taskId} multiple times with the same overall effect on the system as just one of them, hence DELETE is acting idempotently as it should. (The fact that all, or all but the first, DELETE calls return a non-20x doesn't alter that fact.)

like image 41
Uri Avatar answered Nov 14 '22 23:11

Uri