Skip to content

🐛 Improved reliability of email analytics events - #29895

Merged
EvanHahn merged 1 commit into
email-analytics-service-wrapper-should-always-have-a-servicefrom
email-analytics-setJobTimestamp-should-actually-insert-the-job
Aug 13, 2026
Merged

EvanHahn merged 1 commit into
email-analytics-service-wrapper-should-always-have-a-servicefrom
email-analytics-setJobTimestamp-should-actually-insert-the-job

Conversation

@EvanHahn

@EvanHahn EvanHahn commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

ref #29890 (review)

Big picture

We sometimes failed to create the job row for the "missing" job. This could cause:

  • unnecessary extra fetches from Mailgun
  • events to be dropped entirely, if the site was off for awhile

Details

There are four jobs for email analytics:

  1. opened
  2. non-opened
  3. scheduled
  4. missing

Before this change, setJobTimestamp failed to upsert the job row. For the first three job types, it turned out that was fine, because they were already created by previous code paths. But not for the "missing" job!

Before this change, we'd only create the "missing" job row when:

  • no missing events were found
  • there was an error processing the batch

Now, we create it at the right time as intended.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: aa958a6b-d823-4867-b0c1-3b4a0b5781e2

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nx-cloud

nx-cloud Bot commented Aug 11, 2026

Copy link
Copy Markdown

🤖 Nx Cloud AI Fix

Ensure the fix-ci command is configured to always run in your CI pipeline to get automatic fixes in future runs. For more information, please see https://nx.dev/ci/features/self-healing-ci


View your CI Pipeline Execution ↗ for commit c8a7645

Command Status Duration Result
nx run ghost:test:ci:integration ✅ Succeeded 2m 48s View ↗
nx run ghost:test:integration ✅ Succeeded 3m 12s View ↗
nx run ghost:test:e2e ✅ Succeeded 2m 48s View ↗
nx run ghost:test:legacy ✅ Succeeded 2m 10s View ↗
nx run @tryghost/admin:build ✅ Succeeded 2m 5s View ↗
nx run-many -t test:unit -p ghost ✅ Succeeded 30s View ↗
nx run ghost-monorepo:lint:boundaries ✅ Succeeded 21s View ↗
nx run-many -t lint -p ghost,ghost-monorepo ✅ Succeeded 27s View ↗
nx run-many --target=build --projects=tag:publi... ✅ Succeeded 5s View ↗

💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗


☁️ Nx Cloud last updated this comment at 2026-08-13 17:54:54 UTC

@EvanHahn
EvanHahn force-pushed the email-analytics-setJobTimestamp-should-actually-insert-the-job branch from d9e5218 to c5fde44 Compare August 11, 2026 21:18
@EvanHahn
EvanHahn requested a review from cmraible August 11, 2026 21:19
@codecov

codecov Bot commented Aug 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (email-analytics-service-wrapper-should-always-have-a-service@c156792). Learn more about missing BASE report.

Additional details and impacted files
@@                                       Coverage Diff                                       @@
##             email-analytics-service-wrapper-should-always-have-a-service   #29895   +/-   ##
===============================================================================================
  Coverage                                                                ?   75.40%           
===============================================================================================
  Files                                                                   ?     1609           
  Lines                                                                   ?   142364           
  Branches                                                                ?    17614           
===============================================================================================
  Hits                                                                    ?   107355           
  Misses                                                                  ?    33965           
  Partials                                                                ?     1044           
Flag Coverage Δ
e2e-tests 77.45% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@EvanHahn
EvanHahn force-pushed the email-analytics-setJobTimestamp-should-actually-insert-the-job branch 2 times, most recently from abadf2b to 6c6a1b8 Compare August 12, 2026 14:32
@EvanHahn
EvanHahn force-pushed the email-analytics-setJobTimestamp-should-actually-insert-the-job branch from 6c6a1b8 to 3b4fbcf Compare August 12, 2026 16:20
id: new ObjectID().toHexString(),
name: jobName,
[updateField]: date.toISOString(), // force to iso string for sqlite
created_at: date.toISOString(), // force to iso string for sqlite

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thought: this is so subtle, I wonder if we could catch a missing required field like this at compile time somehow 🤔

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this as blocking, but I think we could. Knex supports declaration merging via knex/types/tables and CompositeTableType, which lets us define separate row, insert, and update types. We could make created_at required for inserts but optional for updates, causing the original code here to fail type-checking. Ghost already uses this pattern for gift links and member custom fields.

Quick example pasted from Codex:

import type {Knex} from 'knex';

  interface JobRow {
      id: string;
      name: string;
      status: 'started' | 'finished' | 'failed' | 'queued';
      started_at: Date | string | null;
      finished_at: Date | string | null;
      created_at: Date | string;
      updated_at: Date | string | null;
      metadata: string | null;
      queue_entry: number | null;
  }

  type JobInsert =
      Pick<JobRow, 'id' | 'name' | 'created_at'>
      & Partial<Omit<JobRow, 'id' | 'name' | 'created_at'>>;

  declare module 'knex/types/tables' {
      interface Tables {
          jobs: Knex.CompositeTableType<
              JobRow,             // what SELECT returns
              JobInsert,          // what INSERT accepts
              Partial<JobRow>     // what UPDATE accepts
          >;
      }
  }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this and didn't know about it. Opened #29953 as a draft—not sure about some of the SQLite changes I made there.

@EvanHahn
EvanHahn force-pushed the email-analytics-setJobTimestamp-should-actually-insert-the-job branch from 3b4fbcf to baa8610 Compare August 13, 2026 16:27
@EvanHahn
EvanHahn force-pushed the email-analytics-setJobTimestamp-should-actually-insert-the-job branch from baa8610 to 75179f0 Compare August 13, 2026 17:03
@EvanHahn
EvanHahn force-pushed the email-analytics-setJobTimestamp-should-actually-insert-the-job branch from 75179f0 to c8a7645 Compare August 13, 2026 17:32
@EvanHahn
EvanHahn force-pushed the email-analytics-setJobTimestamp-should-actually-insert-the-job branch from c8a7645 to d372b1d Compare August 13, 2026 17:41
ref #29890 (review)

Big picture
-----------

We sometimes failed to create the job row for the "missing" job. This
could cause:

- unnecessary extra fetches from Mailgun
- events to be dropped entirely, if the site was off for awhile

Details
-------

There are four jobs for email analytics:

1. opened
2. non-opened
3. scheduled
4. missing

Before this change, `setJobTimestamp` failed to upsert the job row. For
the first three job types, it turned out that was fine, because they
were already created by previous code paths. But not for the "missing"
job!

Before this change, we'd only create the "missing" job row when:

- no missing events were found
- there was an error processing the batch

Now, we create it at the right time as intended.
@EvanHahn
EvanHahn force-pushed the email-analytics-setJobTimestamp-should-actually-insert-the-job branch from d372b1d to c660d16 Compare August 13, 2026 17:43
@EvanHahn
EvanHahn merged commit 58af71d into main Aug 13, 2026
57 checks passed
@EvanHahn
EvanHahn deleted the email-analytics-setJobTimestamp-should-actually-insert-the-job branch August 13, 2026 20:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants