Skip to content

Commit 5358c7a

Browse files
committed
drivers: fix task state reported to on_task_change on ttl
In the "ttl tasks" loop of the fifottl and utubettl driver fibers the loop variable shadowed the 'state' module: for _, state in pairs(ttl_states) do ... task = self:delete(task[i_id]):transform(2, 1, state.DONE) Inside the loop `state` is a status string, so `state.DONE` indexes a string, evaluates to nil, and `transform(2, 1, nil)` sets the status field to NULL instead of DONE. The task passed to the user's on_task_change callback with the 'ttl' event was therefore malformed. Rename the loop variable to `task_state`. Closes #255
1 parent 03cece7 commit 5358c7a

4 files changed

Lines changed: 71 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
1313

1414
### Fixed
1515

16+
- The `on_task_change` callback got an expired task with a `NULL` status
17+
instead of `DONE` (`fifottl`, `utubettl`) (#255).
18+
1619
## [1.5.0] - 2026-07-10
1720

1821
This release introduces tube-level grants for roles (supported by all default

queue/abstract/driver/fifottl.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,9 +109,9 @@ local function fifottl_fiber_iteration(self, processed)
109109
end
110110

111111
-- ttl tasks
112-
for _, state in pairs(ttl_states) do
113-
task = self.space.index.watch:min{ state }
114-
if task ~= nil and task[i_status] == state then
112+
for _, task_state in pairs(ttl_states) do
113+
task = self.space.index.watch:min{ task_state }
114+
if task ~= nil and task[i_status] == task_state then
115115
if now >= task[i_next_event] then
116116
task = self:delete(task[i_id]):transform(2, 1, state.DONE)
117117
self:on_task_change(task, 'ttl')

queue/abstract/driver/utubettl.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,9 @@ local function utubettl_fiber_iteration(self, processed)
236236
end
237237

238238
-- ttl tasks
239-
for _, state in pairs(ttl_states) do
240-
task = self.space.index.watch:min{ state }
241-
if task ~= nil and task[i_status] == state then
239+
for _, task_state in pairs(ttl_states) do
240+
task = self.space.index.watch:min{ task_state }
241+
if task ~= nil and task[i_status] == task_state then
242242
if now >= task[i_next_event] then
243243
task = self:delete(task[i_id]):transform(2, 1, state.DONE)
244244
self:on_task_change(task, 'ttl')

t/250-otc-cb-ttl.t

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!/usr/bin/env tarantool
2+
local test = require('tap').test()
3+
test:plan(2)
4+
5+
local fiber = require('fiber')
6+
7+
local tnt = require('t.tnt')
8+
tnt.cfg{}
9+
10+
local engine = os.getenv('ENGINE') or 'memtx'
11+
12+
local queue = require('queue')
13+
local state = require('queue.abstract.state')
14+
15+
-- In the "ttl tasks" loop of the driver fiber the loop variable shadowed the
16+
-- 'state' module, so `state.DONE` was indexing a string and evaluated to nil.
17+
-- As a result the task reported to the on_task_change callback had its status
18+
-- field set to NULL instead of state.DONE.
19+
local function check_ttl_status(test, tube_name, driver, put_opts)
20+
local ttl_task
21+
22+
local tube = queue.create_tube(tube_name, driver, {
23+
engine = engine,
24+
ttl = 0.1,
25+
on_task_change = function(task, stats_data)
26+
if stats_data == 'ttl' then
27+
ttl_task = task
28+
end
29+
end
30+
})
31+
32+
tube:put({'expired'}, put_opts)
33+
34+
local deadline = fiber.clock() + 30
35+
while ttl_task == nil and fiber.clock() < deadline do
36+
fiber.sleep(0.05)
37+
end
38+
39+
if ttl_task == nil then
40+
test:fail('on_task_change is called with the "ttl" event')
41+
test:fail('the expired task is reported in the DONE state')
42+
return
43+
end
44+
45+
test:ok(true, 'on_task_change is called with the "ttl" event')
46+
test:is(ttl_task[2], state.DONE,
47+
'the expired task is reported in the DONE state')
48+
end
49+
50+
test:test('fifottl', function(test)
51+
test:plan(2)
52+
check_ttl_status(test, 'otc_ttl_fifottl', 'fifottl', {})
53+
end)
54+
55+
test:test('utubettl', function(test)
56+
test:plan(2)
57+
check_ttl_status(test, 'otc_ttl_utubettl', 'utubettl', {utube = 'u'})
58+
end)
59+
60+
tnt.finish()
61+
os.exit(test:check() and 0 or 1)
62+
-- vim: set ft=lua :

0 commit comments

Comments
 (0)