Redis append_event stamps last_update_time with the wall clock, not the event timestamp
Maintainer thường phản hồi trong vòng 5 ngày
@sanketpatil06 đang làm issue này rồi.
Từ ngày 28/9/2026.
Đánh giá
- Độ khó
- 2/5
- Thời gian dự kiến
- 1-3 giờ
- Mức phù hợp với người mới
- 88/100
Hướng nghiên cứu
Bắt đầu tại src/google/adk/integrations/redis/_redis_session_service.py, quanh append_event, và so sánh cách xử lý timestamp của nó với các backend phiên khác. Chạy tests/unittests/sessions/test_session_service.py và kiểm tra tests/unittests/sessions/_conformance.py để tìm mục phân kỳ của Redis. Hoàn tất khi phiên Redis và bản sao được tải lại của nó sử dụng timestamp của sự kiện, đồng thời bài kiểm tra tính tuân thủ chạy qua mà không có ngoại lệ Redis.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
🔴 Required Information
Describe the Bug:
RedisSessionService.append_event() sets session.last_update_time to time.time() instead of the appended event's own timestamp. The other three session backends store the event's timestamp:
| backend | what it stores |
|---|---|
InMemorySessionService |
event.timestamp (in_memory_session_service.py:357-364) |
SqliteSessionService |
event_timestamp from event.timestamp (sqlite_session_service.py:433, :515-519) |
DatabaseSessionService |
event_timestamp, reloaded into last_update_time (database_session_service.py:976-1010) |
RedisSessionService |
time.time() (_redis_session_service.py:343) |
last_update_time is not cosmetic. It is the sort key list_sessions documents as "Sessions are ordered by last update time, oldest first" (base_session_service.py:102-118), and the Redis backend sorts on (s.last_update_time, s.user_id, s.id) (_redis_session_service.py:316-318).
The repository already records this as a known divergence. tests/unittests/sessions/_conformance.py registers the redis backend with the entry test_session_last_update_time_updates_on_event, and the harness docstring states that a divergence "becomes a defect anyone can pick up, and whoever fixes the backend has to delete the entry in the same change" (_conformance.py:15-31). That is the harness's own statement of the expected behaviour, marked unfixed.
Steps to Reproduce:
- Use
RedisSessionServiceas the session backend, then create a session. - Append an
Eventwhosetimestamppredates now — produced earlier, then replayed, re-delivered or imported. ADK re-delivers the same event object to a second session reference, which is whyInMemorySessionService.append_eventdedupes on event equality (in_memory_session_service.py:344-355). - Read
session.last_update_time, or calllist_sessions.
No Redis server is required; tests/unittests/integrations/redis/_fake_redis.py is an in-process stand-in.
Expected Behavior:
session.last_update_time equals event.timestamp, and the reloaded session agrees. The contract test asserts exactly this (tests/unittests/sessions/test_session_service.py:1573-1600): it builds an event at original_update_time + 10 and asserts both the in-memory and reloaded values equal it.
Observed Behavior:
The stored value is the wall clock at append time. The contract test on main at 9625b06:
XFAIL ...test_session_last_update_time_updates_on_event[redis] - Redis stamps the session with the wall clock instead of the appended event's timestamp.
5 passed, 1 xfailed
The five passing parameters are the other backends. A regression test that pins the clock far from the event's own timestamp fails by exactly the pinned offset:
E assert 1790353307.6994162 == 1790353207.6994162 ± 1.0e-06
Deterministic consequences:
- Two sessions that received the identical event report different activity times, breaking the re-delivery semantics the in-memory backend was built around.
- A session persisted via one backend and read via another (
src/google/adk/sessions/migration/) shows the Redis session jumping forward by however long the event sat in a queue, while SQLite does not. list_sessionsordering is wrong for any event that predates its append.
Optional information
Environment Details:
- ADK Library Version:
mainat9625b06c9a1be6b9ecd85225657690ae5c0e9d3e - Desktop OS: macOS
- Python Version: 3.14 locally; CI covers 3.10 through 3.14
- LiteLLM: N/A (no model call involved)
Regression: Not recent. The line has always read time.time(); the divergence entry documents it as long-standing.
Minimal reproduction:
from unittest import mock
from google.adk.events.event import Event
from google.adk.integrations.redis._config import RedisSessionServiceConfig
from google.adk.integrations.redis._redis_session_service import RedisSessionService
import pytest
@pytest.mark.asyncio
async def test_append_event_stamps_session_with_event_timestamp(session_service):
session = await session_service.create_session(app_name="app1", user_id="u1")
event_timestamp = session.last_update_time + 10
event = Event(author="agent", invocation_id="inv1", timestamp=event_timestamp)
with mock.patch("google.adk.integrations.redis._redis_session_service.time") as clock:
clock.time.return_value = event_timestamp + 100
await session_service.append_event(session, event)
assert session.last_update_time == pytest.approx(event_timestamp, abs=1e-6)
How often: Always (100%).
Scope note
This is the last_update_time defect only. The divergences map has a second Redis entry, test_append_event_to_unknown_session_raises_session_not_found, which is a separate defect: append_event writes the session key unconditionally (:384-390), so appending to a deleted, expired or never-stored session recreates it instead of raising SessionNotFoundError. That one overlaps open PR #7140, which owns those lines, and is out of scope here.
- Ngôn ngữ chính
- Python
- Star
- 21.6k
- Fork
- 4k
- Merge trung bình
- 12 giờ 6 phút
- Pull request đã merge (30 ngày)
- 4
Chuẩn bị môi trường
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của google/adk-python
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 84/100
google/adk-python#7334 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 5 ngày
-
GoogleOidcVerifier treats string "false" as a verified email claimCó thể đã có người làm @surajksharma07 đã nhận 1 ngày trước. Đang mởcore
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
google/adk-python#7289 · 5 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 5 ngày
-
RestApiTool raises uncaught KeyError when a required path param is omittedCó thể đã có người làm @llalitkumarrr đã nhận 1 ngày trước. Đang mởtools
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
google/adk-python#7282 · 2 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 5 ngày
-
CredentialsManager should also extract scopes when populating auth schemesCó thể đã có người làm @sanketpatil06 đã nhận 4 ngày trước. Đang mởcore needs review
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
google/adk-python#7266 · 2 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 5 ngày
-
OAuth2 Discovery method fails because FastMCP with GoogleProvider (OAuth) returns issuerUrl with trailing slashCó thể đã có người làm @sanketpatil06 đã nhận 4 ngày trước. Đang mởmcp
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
google/adk-python#7265 · 3 bình luận · 1 người được giao ·
Maintainer thường phản hồi trong vòng 5 ngày
Tất cả issue của google/adk-python
Issue tương tự
-
[Bug] @deck.gl/arcgis dist import resolves to unpublished @deck.gl/core source path (9.3.11, 9.4.0)Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
workflow: a tick's dispatch counts as 'only this step', and no review self-grants a round unattendedĐang mởworkflow
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
kristofdegrave/homeassistant-smart-charging#1505 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
New Submission: TropWATERĐang mởmetadata submission
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
-
Wrongly named dashboard variableĐang mởbug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 65/100
canonical/content-cache-operator#163 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
[submission]Đang mởsubmission
Độ khó 1/5 Dưới một giờ Mức phù hợp với người mới 65/100
leanprover/lean-eval-submissions#1852 ·
Maintainer thường phản hồi trong vòng 1 ngày