Compare commits

...

1 Commits

Author SHA1 Message Date
Elizabeth Thompson
59f36997cf fix(reports): pre-commit tab permalinks before state machine transaction
When a dashboard report targets specific tabs, BaseReportState calls
CreateDashboardPermalinkCommand inside the outer @transaction() on
AsyncExecuteReportScheduleCommand.run(). The @transaction() nesting guard
(g.in_transaction) causes the command to only flush the permalink INSERT,
leaving the row invisible to Playwright's separate DB connection. Flask
returns a 404 from dashboard_permalink, <body class="standalone"> never
appears, and the screenshot times out after 600 s.

Fix: remove @transaction() from AsyncExecuteReportScheduleCommand.run()
and add a pre-warm call to get_dashboard_urls() before the state machine
starts. Executed outside any transaction, the call lets
CreateDashboardPermalinkCommand commit normally via its own @transaction().
The state machine's subsequent call to get_dashboard_urls() finds the
already-committed row through get_entry() (same deterministic UUID) and
returns it without a second INSERT. ReportScheduleStateMachine.run()
retains its own @transaction() and remains the outermost transaction owner.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-16 00:15:23 +00:00

View File

@@ -1157,7 +1157,6 @@ class AsyncExecuteReportScheduleCommand(BaseCommand):
self._scheduled_dttm = scheduled_dttm
self._execution_id = UUID(task_id)
@transaction()
def run(self) -> None:
try:
self.validate()
@@ -1170,6 +1169,21 @@ class AsyncExecuteReportScheduleCommand(BaseCommand):
)
user = security_manager.find_user(username)
with override_user(user):
# Pre-commit any permalink rows before the state machine's
# @transaction() opens. When called inside a transaction,
# CreateDashboardPermalinkCommand only flushes (not commits),
# leaving the row invisible to Playwright's separate DB
# connection. Running get_dashboard_urls() here — outside any
# transaction — lets the command commit normally. The state
# machine's inner call to get_dashboard_urls() hits get_entry()
# for the same deterministic UUID and returns the
# already-committed row without a second INSERT.
if self._model.dashboard_id:
BaseReportState(
self._model, self._scheduled_dttm, self._execution_id
).get_dashboard_urls()
start_time = datetime.utcnow()
with override_user(user):
ReportScheduleStateMachine(