Skip to main content

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โ€‹

  1. Creates a unique instance ID based on the device ID
  2. Starts a new Durable Functions orchestration running BaseOrchestrationFunction
  3. Passes the device configuration as input

Stopping an Orchestrationโ€‹

  1. Terminates the running orchestration instance
  2. Updates the durable entity to reflect the stopped state

Redeploying an Orchestrationโ€‹

  1. Terminates the existing instance
  2. Starts a fresh instance with updated configuration
  3. 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 CameraState durable 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:

CommandActivity FunctionPurpose
PTZ MovePanTiltZoomCameraMove camera to specific pan/tilt/zoom
HomeMoveCameraHomeReturn camera to home position
FocusFocusCameraAdjust camera focus
BrightnessSetCameraBrightnessAdjust camera brightness
Guard TourGuardTourToggleInOrchestrationEnable/disable guard tour
StatusCameraStatusQuery 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.