"""Redis delivery checks, enabled by FLUKSIO_TEST_REDIS_HOST (and optional PORT).""" import os import uuid from concurrent.futures import ThreadPoolExecutor import pytest import redis from fluksio.flow.queue import RedisWorkQueue, WorkItem @pytest.fixture def queue(): host = os.environ.get("FLUKSIO_TEST_REDIS_HOST") if not host: pytest.skip("Set FLUKSIO_TEST_REDIS_HOST to run Redis integration checks") queue = RedisWorkQueue( host=host, port=int(os.environ.get("FLUKSIO_TEST_REDIS_PORT", "6379")), namespace=f"test-queue-{uuid.uuid4().hex}", ) try: yield queue finally: keys = list(queue._redis.scan_iter(match=f"{queue._ns}:*")) if keys: queue._redis.delete(*keys) queue.close() def test_concurrent_promotions_deliver_each_due_item_once(queue): for i in range(150): queue.add_delayed( WorkItem(kind="cascade", node=f"f.n{i}", flow="f", outputs={"f.x": i}), 100.0, ) queue.add_delayed(WorkItem(kind="cascade", node="f.later", flow="f"), 300.0) with ThreadPoolExecutor(max_workers=2) as pool: moved = list(pool.map(queue.move_due, [200.0, 200.0])) assert sorted(moved) == [50, 100] assert queue.move_due(200.0) == 0 assert queue.next_due() == 300.0 claimed = queue.claim(200, 10, due_only=True) assert len(claimed) == 150 assert {item.outputs["f.x"] for item in claimed} == set(range(150)) assert all(item.not_before == 100.0 for item in claimed) assert all(item.entry_id.startswith("due:") for item in claimed) def test_a_refused_stream_write_keeps_the_timer_for_retry(queue): queue.add_delayed(WorkItem(kind="cascade", node="f.stop", flow="f"), 100.0) # A Redis command error does not roll a Lua script back. The stream write # must succeed before the delayed entry is removed. queue._redis.delete(queue._due_stream) queue._redis.set(queue._due_stream, "not a stream") with pytest.raises(redis.ResponseError, match="WRONGTYPE"): queue.move_due(200.0) assert queue.next_due() == 100.0 queue._redis.delete(queue._due_stream) queue._ensure_group() assert queue.move_due(200.0) == 1 assert queue.move_due(200.0) == 0 assert [item.node for item in queue.claim(10, 10, due_only=True)] == ["f.stop"]