Skip to content

Commit 863f558

Browse files
committed
feat: add concurrent option to utube
Also adds support for taking from a specific sub-queue by passing `{ utube = '...' }` to the `:take` method.
1 parent 593c9f6 commit 863f558

File tree

2 files changed

+46
-19
lines changed

2 files changed

+46
-19
lines changed

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -127,23 +127,24 @@ options are equal.
127127

128128
The main idea of this queue backend is the same as in a `fifo` queue:
129129
the tasks are executed in FIFO order.
130-
However, tasks may be grouped into sub-queues.
130+
131+
However, tasks may be grouped into sub-queues. Sub-queues split the task
132+
stream according to the sub-queue name. Each sub-queue is executed in strict
133+
FIFO order. By default, only one task per sub-queue may be taken at any time.
131134

132135
The following options can be specified when creating a `utube` queue:
136+
* `concurrent` - number - the number of concurrent tasks per sub-queue
137+
(defaults to 1)
133138
* `temporary` - boolean - if true, the contents of the queue do not persist
134139
on disk
135140
* `if_not_exists` - boolean - if true, no error will be returned if the tube
136141
already exists
137142
* `on_task_change` - function name - a callback to be executed on every
138143
operation
139144

140-
The following options can be specified when putting a task in a `utube`
141-
queue:
145+
The following options are supported for the `:put` and `:take` methods of
146+
a `utube` queue:
142147
* `utube` - the name of the sub-queue.
143-
Sub-queues split the task stream according to the sub-queue name: it is
144-
not possible to take two tasks
145-
out of a sub-queue concurrently, each sub-queue is executed in strict
146-
FIFO order, one task at a time.
147148

148149
`utube` queue does not support:
149150
* task priorities (`pri`)

queue/abstract/driver/utube.lua

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@ function tube.create_space(space_name, opts)
4242
end
4343

4444
-- start tube on space
45-
function tube.new(space, on_task_change)
45+
function tube.new(space, on_task_change, opts)
4646
on_task_change = on_task_change or (function() end)
4747
local self = setmetatable({
4848
space = space,
49+
concurrent = opts.concurrent or 1,
4950
on_task_change = on_task_change,
5051
}, { __index = method })
5152
return self
@@ -65,21 +66,46 @@ function method.put(self, data, opts)
6566
return task
6667
end
6768

69+
-- check concurrency of a sub-queue
70+
function method.is_throttled(self, utube)
71+
if self.concurrent == 1 then
72+
local taken = self.space.index.utube:min{state.TAKEN, utube}
73+
return taken ~= nil and taken[3] == utube
74+
elseif self.concurrent ~= 1/0 then
75+
local num_taken = self.space.index.utube:count{state.TAKEN, utube}
76+
return num_taken == self.concurrent
77+
end
78+
return false
79+
end
80+
6881
-- take task
69-
function method.take(self)
70-
for s, task in self.space.index.status:pairs(state.READY,
71-
{ iterator = 'GE' }) do
72-
if task[2] ~= state.READY then
73-
break
82+
function method.take(self, opts)
83+
local task
84+
if opts and opts.utube then
85+
if not self:is_throttled(opts.utube) then
86+
local t = self.space.index.utube:min{state.READY, opts.utube}
87+
if t and t[2] == state.READY and t[3] == opts.utube then
88+
task = t
89+
end
7490
end
75-
76-
local taken = self.space.index.utube:min{state.TAKEN, task[3]}
77-
if taken == nil or taken[2] ~= state.TAKEN then
78-
task = self.space:update(task[1], { { '=', 2, state.TAKEN } })
79-
self.on_task_change(task, 'take')
80-
return task
91+
else
92+
local utubes = {}
93+
for s, t in self.space.index.status:pairs(state.READY) do
94+
local utube = t[3]
95+
if not utubes[utube] then
96+
if not self:is_throttled(utube) then
97+
task = t
98+
break
99+
end
100+
utubes[utube] = true
101+
end
81102
end
82103
end
104+
if task then
105+
task = self.space:update(task[1], { { '=', 2, state.TAKEN } })
106+
self.on_task_change(task, 'take')
107+
return task
108+
end
83109
end
84110

85111
-- touch task

0 commit comments

Comments
 (0)