Orchestration Lifecycle
The Image Acquisition Engine uses an eternal orchestration pattern โ each camera runs an infinite loop that continuously captures images until explicitly terminated. This is the core pattern of the entire system.
Eternal Orchestration Patternโ
VapixOrchestratorโ
The VapixOrchestrator class manages the lifecycle of orchestration instances:
Starting an Orchestrationโ
- Creates a unique instance ID based on the device ID
- Starts a new Durable Functions orchestration running
BaseOrchestrationFunction - Passes the device configuration as input
Stopping an Orchestrationโ
- Terminates the running orchestration instance
- Updates the durable entity to reflect the stopped state
Redeploying an Orchestrationโ
- Terminates the existing instance
- Starts a fresh instance with updated configuration
- The new instance picks up the latest settings (acquisition rate, image type, etc.)
BaseOrchestrationFunction โ The Main Loopโ
BaseOrchestrationFunction is the longest and most critical file (~350 lines). It orchestrates each iteration of the capture loop:
Step 1: Initializeโ
- Reads the current
CameraStatedurable entity - Loads the device configuration from the orchestration input
- Determines the active acquisition mode and its settings
Step 2: Check Command Queueโ
Before capturing images, the orchestration checks for pending commands on the CameraState entity:
| Command | Activity Function | Purpose |
|---|---|---|
| PTZ Move | PanTiltZoomCamera | Move camera to specific pan/tilt/zoom |
| Home | MoveCameraHome | Return camera to home position |
| Focus | FocusCamera | Adjust camera focus |
| Brightness | SetCameraBrightness | Adjust camera brightness |
| Guard Tour | GuardTourToggleInOrchestration | Enable/disable guard tour |
| Status | CameraStatus | Query full camera status |
Commands are dequeued from the entity and executed as activity functions. This allows the Admin API or frontend to send PTZ commands that get picked up during the next orchestration cycle.
Step 3: Acquire Imagesโ
Based on the current mode, the appropriate mode handler is called (see Acquisition Modes).
Step 4: Mode Transitionsโ
The orchestration checks if a mode transition is needed:
Step 5: Health Checkโ
- If the camera's online/offline status changed, submit the new status to ESRI feature layers
- Sync the current entity state to Table Storage via
DurableDataStoreService
Step 6: Sleep & Continueโ
- Calculate the next wake-up time based on the acquisition rate
- Call
ContinueAsNew()to restart the loop with fresh state - This pattern avoids history growth โ each iteration starts clean
Why ContinueAsNew()?โ
Durable Functions persist orchestration history. Without ContinueAsNew(), a camera running for days would accumulate millions of history entries. ContinueAsNew() resets the history at each iteration, keeping the orchestration lightweight while maintaining the eternal loop.
Concurrencyโ
The Netherite backend is configured in host.json:
{
"extensions": {
"durableTask": {
"hubName": "imgacqhub",
"maxConcurrentOrchestratorFunctions": 2000,
"maxConcurrentActivityFunctions": 4000
}
}
}
This allows the engine to run up to 2000 concurrent camera orchestrations with 4000 concurrent activity functions (image captures, PTZ moves, etc.) across 32 partitions.