DEV Community

murray wang
murray wang

Posted on Originally published at gridzen.ai

Will pending verification survive an application restart?

Your onboarding service creates a hosted verification session, writes it as pending with a deadline, and then the process restarts before any callback arrives. The decision you face: is local state durable enough that the restarted process can resume the same session, or do you need to create a new one? This article walks through the synthetic fixture, where a second process opening the same SQLite file sees the same pending row, deadline and grant count. It also shows what a restart must not do: it must not create a duplicate session, invent approval or poll a provider. Everything here is a local, synthetic example; it does not verify real signatures or grant real permissions.

The problem: a restart between creation and callback

In hosted identity onboarding, there is a gap between creating a session and learning its outcome. A deploy, crash or container reschedule can land in that gap. If pending state lived only in memory, the restarted process has no record of the session. Two bad shortcuts follow: create a fresh session, so the user may verify twice and two callbacks compete, or treat the missing record as finished and let the user through. The reader's decision is narrower than it looks: confirm that durable storage, not process memory, owns pending state, and that the restarted process reads that state before acting. The fixture answers this for one case only: the same SQLite database file, reopened by a new Identity instance.

What the fixture actually implements

The downloadable example stores sessions in a SQLite table with id, tenant, subject, status, deadline, granted, grants, policy_version and allow_action, plus an events table keyed by session and event for deduplication. Constructing Identity with a path runs CREATE TABLE IF NOT EXISTS, so reopening an existing file keeps its rows instead of resetting them. create inserts a pending row with deadline now plus timeout; calling create again for the same session id raises a SQLite integrity error rather than silently replacing it, and the command-line entry point reports that as existing_fixture. read returns the stored status, deadline, permission_granted, grant_count, policy_version and allow_action, always with live_permission_changed false. Only synthetic callbacks are accepted: event ids must start with fixture-, mode must be synthetic_fixture and source fixture_callback; anything else raises PRODUCTION_SIGNATURE_VERIFIER_NOT_IMPLEMENTED. The restart test is run with the restart and timeout recovery unit tests named in the guide. This is distinct from the anonymous three-scenario HTTP trial; that trial is not the four-branch downloadable phone example either.

Worked hypothetical scenario

Hypothetically, process A opens a database file and calls create at time 0 with the default 60 second timeout. The created output is mode synthetic_fixture, state simulated, session fixture-session, a hosted_link on an example.invalid domain, link_executable false and next send_real_provider_link_only_after_authorization. Process A then stops. Process B opens a new Identity on the same file and calls read: status pending, deadline 60, permission_granted false, grant_count 0. Nothing was lost and no second session exists. Branch one: a synthetic Approved event arrives at time 1 with policy true. The expected output is status approved, deadline 60, permission_granted true, grant_count 1, live_permission_changed false, policy_version 1, allow_action true. Delivering the same event id again returns identical values, grant_count still 1. Branch two: no callback arrives and process B calls recover at time 61. Expected: status expired, deadline 60, permission_granted false, grant_count 0, next review_or_authorized_provider_refresh, provider_polled false. A later event against an expired session leaves it expired.

Failure handling the caller still owns

The fixture surfaces errors; your application decides what to do with them. A read for a session id that is not in the database raises SESSION_NOT_FOUND, which after a restart usually means the process opened a different file, for example a fresh temporary path or a new container volume. Treat that as a configuration fault to alert on, not as a reason to create a new session silently. An event whose tenant or subject do not match the stored row, or that names an unknown session, raises BINDING_MISMATCH and changes nothing. Recover expires locally and never queries a provider; in a real integration the next step is human review or an authorized status refresh, which you must build and which this example does not establish. A missing callback never becomes approval.

Proposed application design, not implemented behavior

For production, we propose keeping the database on storage that outlives the process, running a startup sweep that reads pending, review and unknown sessions and calls a recover equivalent for those past deadline, and refusing to start if the expected database is absent. You would also need provider-specific signature validation and bounded status reconciliation. None of these are in the fixture. Likewise, permission_granted in the fixture is a local record; synthetic fixture permission is not live business permission, and an Approved status is not unconditional permission to act on a real user.

Acceptance checklist

Before deciding a sandbox integration fits: run the restart and timeout recovery tests and see both pass; confirm a second instance on the same file reads pending with deadline 60 and grant_count 0; confirm a repeated create does not replace the row; confirm a duplicate event keeps grant_count 1; confirm recover after the deadline returns expired with provider_polled false; confirm an unknown session yields SESSION_NOT_FOUND on read and BINDING_MISMATCH on event; and record in writing that signature verification, provider refresh and real permissions remain unbuilt. Passing tests show local state handling only, not production success.

Run the checked synthetic example

Download and extract https://gridzen.ai/downloads/verification-delivery.zip, enter verification_delivery, then run with Python 3.10+. This local example makes no network calls. Use a fresh database for an independent identity run.

python3 delivery.py identity --db /tmp/gridzen-article-fixture.sqlite
Enter fullscreen mode Exit fullscreen mode

Sources and scope

https://gridzen.ai/guides/missing-verification-webhook/
https://gridzen.ai/guides/current-capabilities/
Based on the checked source snapshot and local fixture; proposed application rules are design advice, not proven production behavior. Written with AI assistance and reviewed independently.

curl https://gridzen.ai/console/api/quickstart/trial \
  -H 'Content-Type: application/json' \
  -d '{"task": "identity_onboarding", "scenario": "success"}'
Enter fullscreen mode Exit fullscreen mode

This is synthetic integration testing, not identity verification or production authorization. Real payments are disabled.

Create a free sandbox account ยท Integration guide

Written and tested by the GridZen team with AI assistance.

Top comments (0)