Skip to content

Commit f7529a7

Browse files
author
Artur Shiriev
committed
rename name to topic
1 parent 4fce5d3 commit f7529a7

File tree

6 files changed

+42
-58
lines changed

6 files changed

+42
-58
lines changed

Dockerfile

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,12 @@
11
FROM python:3.13-slim
22

3-
# required for psycopg2
4-
RUN apt update \
5-
&& apt install -y --no-install-recommends \
6-
build-essential \
7-
libpq-dev \
8-
&& apt clean \
9-
&& rm -rf /var/lib/apt/lists/*
10-
113
COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv
124
RUN useradd --no-create-home --gid root runner
135

14-
ENV UV_PYTHON_PREFERENCE=only-system
15-
ENV UV_NO_CACHE=true
6+
ENV UV_PROJECT_ENVIRONMENT=/code/.venv \
7+
UV_NO_MANAGED_PYTHON=1 \
8+
UV_NO_CACHE=true \
9+
UV_LINK_MODE=copy
1610

1711
WORKDIR /code
1812

@@ -26,3 +20,5 @@ COPY . .
2620
RUN chown -R runner:root /code && chmod -R g=u /code
2721

2822
USER runner
23+
24+
RUN uv sync --all-extras --frozen

Justfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sh:
77
docker compose run --service-ports application bash
88

99
test *args: down && down
10-
docker compose run application uv run --no-sync pytest {{ args }}
10+
docker compose run application uv run pytest {{ args }}
1111

1212
build:
1313
docker compose build application

docker-compose.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ services:
55
dockerfile: ./Dockerfile
66
restart: always
77
volumes:
8-
- .:/srv/www/
8+
- .:/code
9+
- /code/.venv
910
depends_on:
1011
redis:
1112
condition: service_healthy

redis_timers/router.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class Router:
1313
def handler[T: pydantic.BaseModel](
1414
self,
1515
*,
16-
name: str | None = None,
16+
topic: str,
1717
schema: type[T],
1818
) -> typing.Callable[
1919
[typing.Callable[[T], typing.Coroutine[None, None, None]]],
@@ -24,7 +24,7 @@ def _decorator(
2424
) -> typing.Callable[[T], typing.Coroutine[None, None, None]]:
2525
self.handlers.append(
2626
Handler(
27-
topic=name or func.__name__,
27+
topic=topic,
2828
schema=schema,
2929
handler=func,
3030
)

tests/test_router.py

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@ class AnotherSchema(pydantic.BaseModel):
1313
count: int
1414

1515

16-
def test_register_handler_with_name() -> None:
16+
def test_register_handler() -> None:
1717
router: typing.Final = Router()
1818

19-
@router.handler(name="test_timer", schema=SomeSchema)
19+
@router.handler(topic="test_timer", schema=SomeSchema)
2020
async def test_handler(data: SomeSchema) -> None: ...
2121

2222
assert len(router.handlers) == 1
@@ -26,27 +26,14 @@ async def test_handler(data: SomeSchema) -> None: ...
2626
assert handler.handler == test_handler
2727

2828

29-
def test_register_handler_without_name() -> None:
30-
router: typing.Final = Router()
31-
32-
@router.handler(schema=SomeSchema)
33-
async def my_timer_handler(data: SomeSchema) -> None: ...
34-
35-
assert len(router.handlers) == 1
36-
handler: typing.Final = router.handlers[0]
37-
assert handler.topic == "my_timer_handler"
38-
assert handler.schema == SomeSchema
39-
assert handler.handler == my_timer_handler
40-
41-
4229
def test_register_handler_multiple_handlers() -> None:
4330
router: typing.Final = Router()
4431
expected_handlers_count: typing.Final = 2
4532

46-
@router.handler(name="handler1", schema=SomeSchema)
33+
@router.handler(topic="handler1", schema=SomeSchema)
4734
async def handler1(data: SomeSchema) -> None: ...
4835

49-
@router.handler(name="handler2", schema=AnotherSchema)
36+
@router.handler(topic="handler2", schema=AnotherSchema)
5037
async def handler2(data: AnotherSchema) -> None: ...
5138

5239
assert len(router.handlers) == expected_handlers_count

tests/test_timers.py

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
DUPLICATE_TIMER_COUNT = 2
1717

1818

19-
class TestPayloadModel(pydantic.BaseModel):
19+
class SomePayloadModel(pydantic.BaseModel):
2020
message: str
2121
count: int
2222

@@ -27,9 +27,9 @@ class AnotherPayloadModel(pydantic.BaseModel):
2727

2828
class HandlerResults:
2929
def __init__(self) -> None:
30-
self.results: list[TestPayloadModel | AnotherPayloadModel] = []
30+
self.results: list[SomePayloadModel | AnotherPayloadModel] = []
3131

32-
def add_result(self, result: TestPayloadModel | AnotherPayloadModel) -> None:
32+
def add_result(self, result: SomePayloadModel | AnotherPayloadModel) -> None:
3333
self.results.append(result)
3434

3535
def clear(self) -> None:
@@ -43,7 +43,7 @@ async def redis_client() -> AsyncGenerator["aioredis.Redis[str]"]:
4343
await client.delete(settings.TIMERS_TIMELINE_KEY, settings.TIMERS_PAYLOADS_KEY)
4444
yield client
4545
finally:
46-
await client.close()
46+
await client.aclose() # type: ignore[attr-defined]
4747

4848

4949
@pytest.fixture
@@ -57,13 +57,13 @@ async def handler_results() -> AsyncGenerator[HandlerResults]:
5757
def timers_instance(redis_client: "aioredis.Redis[str]", handler_results: HandlerResults) -> Timers:
5858
router1 = Router()
5959

60-
@router1.handler(schema=TestPayloadModel)
61-
async def test_handler(data: TestPayloadModel) -> None:
60+
@router1.handler(topic="some_topic", schema=SomePayloadModel)
61+
async def test_handler(data: SomePayloadModel) -> None:
6262
handler_results.add_result(data)
6363

6464
router2 = Router()
6565

66-
@router2.handler(name="another_topic", schema=AnotherPayloadModel)
66+
@router2.handler(topic="another_topic", schema=AnotherPayloadModel)
6767
async def another_handler(data: AnotherPayloadModel) -> None:
6868
handler_results.add_result(data)
6969

@@ -75,25 +75,25 @@ async def another_handler(data: AnotherPayloadModel) -> None:
7575

7676

7777
async def test_set_and_remove_timer(timers_instance: Timers) -> None:
78-
payload = TestPayloadModel(message="test", count=1)
78+
payload = SomePayloadModel(message="test", count=1)
7979
await timers_instance.set_timer(
80-
topic="test_handler", timer_id="test_timer_1", payload=payload, activation_period=datetime.timedelta(seconds=1)
80+
topic="some_topic", timer_id="test_timer_1", payload=payload, activation_period=datetime.timedelta(seconds=1)
8181
)
8282

8383
# Check that timer exists in Redis
8484
timeline_keys, payloads_dict = await timers_instance.fetch_all_timers()
8585
assert len(timeline_keys) == 1
8686
timer_key = timeline_keys[0]
87-
assert timer_key == "test_handler--test_timer_1"
87+
assert timer_key == "some_topic--test_timer_1"
8888

8989
# Check payloads has the timer data
9090
assert timer_key in payloads_dict
9191
payload_data = payloads_dict[timer_key]
92-
parsed_payload = TestPayloadModel.model_validate_json(payload_data)
92+
parsed_payload = SomePayloadModel.model_validate_json(payload_data)
9393
assert parsed_payload == payload
9494

9595
# Remove the timer
96-
await timers_instance.remove_timer(topic="test_handler", timer_id="test_timer_1")
96+
await timers_instance.remove_timer(topic="some_topic", timer_id="test_timer_1")
9797

9898
# Check that timer is removed from Redis
9999
timeline_keys, payloads_dict = await timers_instance.fetch_all_timers()
@@ -102,9 +102,9 @@ async def test_set_and_remove_timer(timers_instance: Timers) -> None:
102102

103103

104104
async def test_handle_ready_timers(timers_instance: Timers, handler_results: HandlerResults) -> None:
105-
payload = TestPayloadModel(message="ready_timer", count=42)
105+
payload = SomePayloadModel(message="ready_timer", count=42)
106106
await timers_instance.set_timer(
107-
topic="test_handler",
107+
topic="some_topic",
108108
timer_id="ready_timer_1",
109109
payload=payload,
110110
activation_period=datetime.timedelta(seconds=0), # Ready immediately
@@ -117,7 +117,7 @@ async def test_handle_ready_timers(timers_instance: Timers, handler_results: Han
117117
assert handler_results.results
118118
assert len(handler_results.results) == 1
119119
result = handler_results.results[0]
120-
assert isinstance(result, TestPayloadModel)
120+
assert isinstance(result, SomePayloadModel)
121121
assert result == payload
122122

123123
# Check that timer was removed from Redis
@@ -127,11 +127,11 @@ async def test_handle_ready_timers(timers_instance: Timers, handler_results: Han
127127

128128

129129
async def test_handle_multiple_ready_timers(timers_instance: Timers, handler_results: HandlerResults) -> None:
130-
payload1 = TestPayloadModel(message="timer_1", count=1)
130+
payload1 = SomePayloadModel(message="timer_1", count=1)
131131
payload2 = AnotherPayloadModel(value="timer_2")
132132

133133
await timers_instance.set_timer(
134-
topic="test_handler",
134+
topic="some_topic",
135135
timer_id="multi_timer_1",
136136
payload=payload1,
137137
activation_period=datetime.timedelta(seconds=0),
@@ -150,9 +150,9 @@ async def test_handle_multiple_ready_timers(timers_instance: Timers, handler_res
150150

151151

152152
async def test_timer_not_ready_yet(timers_instance: Timers, handler_results: HandlerResults) -> None:
153-
payload = TestPayloadModel(message="future_timer", count=99)
153+
payload = SomePayloadModel(message="future_timer", count=99)
154154
await timers_instance.set_timer(
155-
topic="test_handler",
155+
topic="some_topic",
156156
timer_id="future_timer_1",
157157
payload=payload,
158158
activation_period=datetime.timedelta(seconds=10),
@@ -163,16 +163,16 @@ async def test_timer_not_ready_yet(timers_instance: Timers, handler_results: Han
163163
assert len(handler_results.results) == 0
164164
timeline_keys, payloads_dict = await timers_instance.fetch_all_timers()
165165
assert len(timeline_keys) == 1
166-
timer_key = "test_handler--future_timer_1"
166+
timer_key = "some_topic--future_timer_1"
167167
assert timer_key in payloads_dict
168168

169169

170170
async def test_remove_nonexistent_timer(timers_instance: Timers) -> None:
171-
await timers_instance.remove_timer(topic="test_handler", timer_id="nonexistent_timer")
171+
await timers_instance.remove_timer(topic="some_topic", timer_id="nonexistent_timer")
172172

173173

174174
async def test_set_timer_with_invalid_topic(timers_instance: Timers) -> None:
175-
payload = TestPayloadModel(message="test", count=1)
175+
payload = SomePayloadModel(message="test", count=1)
176176

177177
with pytest.raises(RuntimeError, match="Handler is not found"):
178178
await timers_instance.set_timer(
@@ -194,17 +194,17 @@ async def test_empty_timeline_handling(timers_instance: Timers, handler_results:
194194

195195

196196
async def test_duplicate_timer_replacement(timers_instance: Timers, handler_results: HandlerResults) -> None:
197-
payload1 = TestPayloadModel(message="first", count=1)
197+
payload1 = SomePayloadModel(message="first", count=1)
198198
await timers_instance.set_timer(
199-
topic="test_handler",
199+
topic="some_topic",
200200
timer_id="duplicate_timer",
201201
payload=payload1,
202202
activation_period=datetime.timedelta(seconds=10), # Far in future
203203
)
204204

205-
payload2 = TestPayloadModel(message="second", count=2)
205+
payload2 = SomePayloadModel(message="second", count=2)
206206
await timers_instance.set_timer(
207-
topic="test_handler",
207+
topic="some_topic",
208208
timer_id="duplicate_timer",
209209
payload=payload2,
210210
activation_period=datetime.timedelta(seconds=0), # Ready immediately
@@ -214,5 +214,5 @@ async def test_duplicate_timer_replacement(timers_instance: Timers, handler_resu
214214

215215
assert len(handler_results.results) == 1
216216
result = handler_results.results[0]
217-
assert isinstance(result, TestPayloadModel)
217+
assert isinstance(result, SomePayloadModel)
218218
assert result == payload2

0 commit comments

Comments
 (0)