Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions drift/instrumentation/django/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,17 @@ def _handle_replay_request(self, request: HttpRequest, sdk) -> HttpResponse:
logger.warning("[DJANGO_MIDDLEWARE] No replay_trace_id found in headers, proceeding without span")
return self.get_response(request)

# Start time travel as early as possible (inbound request start) to ensure deterministic
# behavior for time-dependent code paths, especially cache key generation (e.g. django-cachalot).
root_timestamp = headers_lower.get("http_x_td_root_timestamp")
if root_timestamp:
try:
from drift.instrumentation.datetime.instrumentation import start_time_travel

start_time_travel(root_timestamp, trace_id=replay_trace_id)
except Exception as e:
logger.debug(f"[DJANGO_MIDDLEWARE] Failed to start time travel from x-td-root-timestamp: {e}")

# Set replay trace context
replay_token = replay_trace_id_context.set(replay_trace_id)

Expand Down
11 changes: 11 additions & 0 deletions drift/instrumentation/fastapi/instrumentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,17 @@ async def _handle_replay_request(

logger.debug(f"[FastAPIInstrumentation] Setting replay trace ID: {replay_trace_id}")

# Start time travel at inbound request start when provided by CLI.
# This prevents time drift before the first outbound span is matched (critical for cache keys).
root_timestamp = headers_lower.get("x-td-root-timestamp")
if root_timestamp:
try:
from drift.instrumentation.datetime.instrumentation import start_time_travel

start_time_travel(root_timestamp, trace_id=replay_trace_id)
except Exception as e:
logger.debug(f"[FastAPIInstrumentation] Failed to start time travel from x-td-root-timestamp: {e}")

# Remove accept-encoding header to prevent compression during replay
# (responses are stored decompressed, compression would double-compress)
if "accept-encoding" in headers_lower:
Expand Down
11 changes: 11 additions & 0 deletions drift/instrumentation/wsgi/handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,17 @@ def _handle_replay_request(
# No trace context in REPLAY mode; proceed without span
return original_wsgi_app(app, environ, start_response)

# Start time travel at inbound request start when provided by CLI.
# This prevents time drift before the first outbound span is matched (critical for cache keys).
root_timestamp = headers_lower.get("x-td-root-timestamp")
if root_timestamp:
try:
from drift.instrumentation.datetime.instrumentation import start_time_travel

start_time_travel(root_timestamp, trace_id=replay_trace_id)
except Exception as e:
logger.debug(f"[WSGI] Failed to start time travel from x-td-root-timestamp: {e}")

# Set replay trace context
replay_token = replay_trace_id_context.set(replay_trace_id)

Expand Down