Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.aspfox.com/llms.txt

Use this file to discover all available pages before exploring further.

All jobs run via Hangfire with PostgreSQL storage. The Hangfire dashboard is at /hangfire (requires is_admin JWT claim).

Job schedule reference

JobCron scheduleBatch sizeWhat it does
trial-expiry0 9 * * * (daily 9:00 AM UTC)100 tenants/runSends 7-day and 1-day trial warning emails. Expires trials that have ended and downgrades tenants to Free.
subscription-sync0 */2 * * * (every 2 hours)All tenants with Stripe subscriptionsFetches current subscription state from Stripe and reconciles with local database. Recovers from missed webhooks.
token-cleanup0 3 * * * (daily 3:00 AM UTC)All expired tokensDeletes expired refresh tokens, password reset tokens, email verification tokens, and magic link tokens.
invitation-cleanup0 4 * * 0 (weekly Sunday 4:00 AM UTC)All expired invitationsRemoves invitations that expired more than 30 days ago. Keeps recently expired ones visible for resend.

Retry behavior

All jobs use the same retry policy: 3 attempts with exponential backoff.
AttemptDelay after failure
1st retry60 seconds
2nd retry300 seconds (5 minutes)
3rd retry900 seconds (15 minutes)
After 3 failed attempts, the job moves to the Failed queue in the Hangfire dashboard and stops retrying automatically.

What to do when a job fails repeatedly

  1. Go to /hangfireFailed Jobs
  2. Click on the failed job to see the full exception and stack trace
  3. Fix the root cause (usually a database connectivity issue, Stripe API error, or configuration problem)
  4. Click Requeue to retry the job immediately
  5. Monitor the job’s next scheduled run to confirm it succeeds
Common causes:
  • token-cleanup fails → usually a PostgreSQL connectivity issue
  • subscription-sync fails → usually a Stripe API rate limit or network issue; retries automatically
  • trial-expiry fails → usually an email delivery issue; check Resend dashboard

Triggering a job manually

From the Hangfire dashboard:
  1. Recurring Jobs tab
  2. Find the job by name
  3. Click Trigger now
The job starts immediately regardless of its scheduled time.

Disabling a job

To disable a job without deleting it:
// Comment out or remove the RecurringJob.AddOrUpdate call in HangfireJobRegistrar.cs
// RecurringJob.AddOrUpdate<TrialExpiryJob>(…)

// Optionally, explicitly remove it so it does not appear in the dashboard:
RecurringJob.RemoveIfExists("trial-expiry");
Restart the API after making this change.

Viewing job history

Hangfire stores the execution history of every job run. From the dashboard:
  • Succeeded — completed runs with duration and timestamp
  • Failed — failed runs with exception details
  • Recurring Jobs — next scheduled run, last execution status
Job history is retained for 7 days by default. Configure the retention period in HangfireConfiguration.cs.