Skip to main content

[Employer Sync 3.1] Skeleton: EmployersSyncService with stubbed mappers

TL;DR: Empty shell of EmployersSyncService — find_in_batches(1000), per-record begin/rescue, JodGig::TimezoneService watermark, Gig::SyncLog write — with every mapping function stubbed to raise UnimplementedError. Each real mapper lands as its own small PR (4.1–4.4).

Context​

The employer sync has the same shape as the existing talent sync: a batch job, an incremental watermark on updated_at, per-record error handling, a Gig::SyncLog row at the end. We want that shell in place first, with every business decision stubbed out — so each mapper can land as its own small, reviewable PR.

Problem​

PR #1634 put service, job, mappers, dedup, and bug-fixes all into one 583-line change. It was hard to review with a mid-level engineer. The redo splits them.

Direction​

Build only the shell. No real business logic in this PR.

Service — JodGig::Users::EmployersSyncService.execute:

  • Read the last successful Gig::SyncLog for this origin/destination pair.
  • Compute the incremental watermark through JodGig::TimezoneService (the service that branch 1642 introduces — coordinate). Never + 8.hours.
  • Call select_employers_in_scope (stubbed — returns an empty relation).
  • find_in_batches(batch_size: 1000) — same size as the talent sync.
  • For each record in a batch, run inside its own begin / rescue — append failures to fail_log, report to Sentry with the user id, continue. Per-record, not per-batch.
  • Inside the per-record block: call map_to_identities_user, upsert_identities_users (single-row), then map_to_org_memberships, upsert_org_memberships, then map_to_org_outlet_assignments, upsert_org_outlet_assignments. All stubbed for now.
  • End by writing a Gig::SyncLog row with is_successful = fail_log.blank?.

Job — JodGig::Users::EmployersSyncJob:

  • Sidekiq::Job; sidekiq_options(queue: :low, retry: 0, dead: true, backtrace: 10).
  • One line: JodGig::Users::EmployersSyncService.execute().

Scheduler — add the entry in config/sidekiq_scheduler.yml. Cadence is set by issue 5.3 (hourly); for now register it with a cron placeholder noting "set in 5.3."

Stubs. Each of the methods below lives on the service and raises Errors::UnimplementedError with the issue reference:

  • select_employers_in_scope → "implemented in 4.1"
  • map_to_identities_user(jodgig_user) → "implemented in 4.2"
  • upsert_identities_users(rows) → "implemented in 4.2"
  • map_to_org_memberships(...) → "implemented in 4.3"
  • upsert_org_memberships(rows) → "implemented in 4.3"
  • map_to_org_outlet_assignments(...) → "implemented in 4.4"
  • upsert_org_outlet_assignments(rows) → "implemented in 4.4"
  • resolve_owner_per_company(...) → "implemented in 4.3"

Gig::SyncLog enum — add jodgig_users_employers to origin_table.

Acceptance​

  • Service, job, and scheduler entry exist; follow AGENTS.md patterns.
  • Per-record begin / rescue is wired in the batch loop (not per-batch).
  • Stubs raise UnimplementedError with the issue reference in the message.
  • The sync runs in QA against an empty scope and writes a clean Gig::SyncLog row (is_successful: true).

Depends on​

  • 2.1, 2.2 (schema must exist before the sync touches it)