First to Site
Release 3.8

Daily SPEAR Refresh Cron

Scheduled background refresh of SPEAR milestone data for non-closed untitled projects

Overview

SPEAR milestone data underpins every predicted-title-date calculation on the platform. Before 3.8 the data was only refreshed when something actively triggered an enrichment (project save, order creation, parcel lookup). Projects that sat idle for weeks kept stale SPEAR data, which meant stale predicted title dates.

Release 3.8 adds a daily cron endpoint that iterates all non-closed untitled projects and dispatches an async SPEAR refresh per project. Default schedule: 2pm server time.

What Changed

New endpoint: GET /api/cron/project/update-untitled-spear

Pulls project rows matching all of:

  • status.category.tag != 'closed' (project is active)
  • titleStatus IS NULL, or titleStatus.tag IN ('untitled', 'tba'), or predictedTitleDate IS NULL

For each match, dispatches an UpdateUntitledSpearData message to the async messenger transport. Accepts ?limit=N to process only the top N for debugging; default is unbounded (processes everything).

Returns JSON with {dispatched: N} so the cron log shows how many projects got queued.

New async message: App\Message\UpdateUntitledSpearData

Simple DTO carrying projectId. Routed to async in messenger.yaml. The handler re-loads the project by id and calls:

  1. ProjectInsightEnrichmentService::enrich($project) - re-fetches parcel insights from dossier-api with the estate-resolved title / street offsets.
  2. SpearMilestoneService::syncProjectMilestones($project) - refreshes the raw milestone rows.

Both calls are idempotent. If SPEAR has nothing new, the project is a no-op.

Why async per-project

Running all refreshes in the cron request itself would:

  • Tie the HTTP request up for minutes and risk timeouts.
  • Block other cron entries that land at the same wall-clock time.
  • Serialise what should naturally parallelise across the two messenger workers on fts1.

Dispatching one message per project lets the messenger workers drain the queue at their own pace, and a failure on project X does not poison projects Y + Z.

Cron schedule

On fts1 (root crontab):

0 14 * * * /usr/bin/curl --silent https://platform.ftsonline.com.au/api/cron/project/update-untitled-spear &>/dev/null

Daily at 14:00 server time. The endpoint is idempotent so a re-trigger or overlap is safe.