Skip to content

Job Lifecycle

The Job model represents a staffing position (mapped from Salesforce msf__Job__c) whose lifecycle hooks drive Salesforce synchronisation, geocoding, worker notifications, screening creation, and cache invalidation.


State Machine

Covers status-field transitions. Side effects for each transition are detailed in the Hook Reference Table below.

stateDiagram-v2
    [*] --> DRAFT: Created
    DRAFT --> ACTIVE: Published
    ACTIVE --> ARCHIVED: Archived
    ACTIVE --> DRAFT: Unpublished

Hook Flowchart

Covers all hooks across all lifecycle events, with conditions and triggered actions.

flowchart TD
    subgraph JobPosition
        JP_AC[AFTER_CREATE]
        JP_AC --> JP_H1["schedule_wage_population\nEnqueue wage fetch from BC"]
    end

    subgraph Job
        AU[AFTER_UPDATE]

        AU -->|"status == ACTIVE"| H1["on_status_active_sync_to_salesforce\nCREATE or UPDATE in Salesforce"]
        AU -->|"status == ACTIVE AND\n(status changed OR location changed)"| H2["geocode_and_recompute_job_distances\nGeocode location, recompute distances"]
        AU -->|"status == ACTIVE AND\nstatus changed"| H3["notify_matching_workers_on_publish\nNotify matching workers"]
        H3 --> H3a["create_job_screening\nCreate JobScreening"]
        AU -->|"status == ACTIVE AND\nstatus changed"| H4["broadcast_job_published_cache_invalidation\nBroadcast cache invalidation via sockets"]
        AU -->|"status == ACTIVE AND\n(start_date changed OR end_date changed)"| H5["notify_saved_workers_on_date_change\nNotify workers who saved this job"]
    end

    subgraph JobMediaFile
        JMF_AD[AFTER_DELETE]
        JMF_AD --> JMF_H1["clean_storage\nDelete file from storage"]
    end

Hook Reference Table

Event Condition Handler Side Effects
JobPosition
AFTER_CREATE schedule_wage_population Enqueues fetch_position_wages task to populate age-specific wages from Business Central
Job
AFTER_UPDATE status == ACTIVE on_status_active_sync_to_salesforce If already in Salesforce and a sync field changed → sync_object_to_salesforce (UPDATE). If not yet in Salesforce → sync_object_to_salesforce (CREATE). Sync fields: status, position, description
AFTER_UPDATE status == ACTIVE AND (status changed OR location changed) geocode_and_recompute_job_distances Enqueues geocode_and_recompute_job task when the job has a named location
AFTER_UPDATE status == ACTIVE AND status changed notify_matching_workers_on_publish Enqueues notify_matching_workers_for_job task and create_job_screening task
AFTER_UPDATE status == ACTIVE AND status changed broadcast_job_published_cache_invalidation Calls UserEventsResolver().resolve(self) to broadcast cache invalidation to workers via sockets
AFTER_UPDATE status == ACTIVE AND (start_date changed OR end_date changed) notify_saved_workers_on_date_change Enqueues notify_saved_job_updated_task to notify workers who saved the job
JobMediaFile
AFTER_DELETE clean_storage Deletes the associated file from default_storage (suppresses exceptions)

Notes

  • All heavy side effects (Salesforce sync, geocoding, notifications, screening creation) are executed asynchronously via Celery tasks (.delay()).
  • The on_status_active_sync_to_salesforce hook fires on every update while status is ACTIVE, not only on status transitions. It checks internally whether sync fields have changed or whether the object needs initial creation in Salesforce.
  • Three hooks share the same trigger (status == ACTIVE AND status changed): notify_matching_workers_on_publish, broadcast_job_published_cache_invalidation, and geocode_and_recompute_job_distances (when combined with location change). Django-lifecycle does not guarantee execution order between separate @hook methods on the same event.
  • notify_matching_workers_on_publish bundles two distinct side effects (worker notification and screening creation) in a single handler.
  • JobMediaFile.clean_storage silently suppresses all exceptions during file deletion to avoid blocking model deletion.