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_salesforcehook 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 == ACTIVEANDstatuschanged):notify_matching_workers_on_publish,broadcast_job_published_cache_invalidation, andgeocode_and_recompute_job_distances(when combined with location change). Django-lifecycle does not guarantee execution order between separate@hookmethods on the same event. notify_matching_workers_on_publishbundles two distinct side effects (worker notification and screening creation) in a single handler.JobMediaFile.clean_storagesilently suppresses all exceptions during file deletion to avoid blocking model deletion.