-
Notifications
You must be signed in to change notification settings - Fork 4
Plugin SDK Threading
Plugins run on a dedicated engine thread. Understanding the threading model is essential for writing correct, performant plugin code.
Plugin starts on engine thread
|
All lifecycle methods run on engine thread
|
Engine write operations must run on engine thread
|
External threads must queue work to engine thread
Key principles:
- Write operations (create, update, delete entities) must run on the engine thread
- Entity cache reads are thread-safe but have I/O considerations (see below)
- Queries (ReportManager) are I/O bound and should run on background threads, not the engine thread
- Lifecycle methods (OnPluginLoaded, OnQueryReceived, etc.) run on the engine thread
- External callbacks (System.Timers.Timer, Task continuations, ThreadPool work items) run on different threads
GetEntity and I/O:
-
GetEntity(guid)orGetEntity(guid, query: true)- May query the server if entity is not cached (I/O operation) -
GetEntity(guid, query: false)- Returns only from cache, returns null if not cached
Every plugin runs on a dedicated thread where Engine operations are performed. This thread:
- Executes all lifecycle methods (OnPluginLoaded, OnPluginStart, Dispose)
- Processes incoming events and queries
- Handles request callbacks
- Does not have a
System.Threading.SynchronizationContext
Engine thread constraints:
- Avoid blocking I/O operations (network calls, file operations, database queries)
- Avoid long-running computations
- Use only for entity operations and configuration changes
- Perform I/O and heavy processing on background threads
Use these methods to marshal work from external threads to the engine thread.
| Method | Behavior | Returns |
|---|---|---|
QueueUpdate(Action) |
Queues action to engine thread, returns immediately | void |
QueueUpdateAndWait(Action) |
Queues action and blocks until completed | void |
Use QueueUpdate when you do not need to wait for the result:
// Example: Timer callback runs on a ThreadPool thread
private void OnTimerElapsed(object sender, ElapsedEventArgs e)
{
// Queue to engine thread - returns immediately
Engine.QueueUpdate(() =>
{
var entity = Engine.GetEntity<CustomEntity>(m_entityGuid);
entity.RunningState = State.Running;
});
// Execution continues immediately without waiting
}Use QueueUpdateAndWait when you need to wait for a write operation to complete before continuing:
// Example: External thread needs to update an entity and confirm success
private bool TryUpdateEntityState(Guid entityGuid, State newState)
{
bool success = false;
Engine.QueueUpdateAndWait(() =>
{
try
{
var entity = Engine.GetEntity<CustomEntity>(entityGuid);
entity.RunningState = newState;
success = true;
}
catch (Exception ex)
{
Logger.TraceError(ex, "Failed to update entity state");
}
});
return success;
}Use the IsEngineThread property to determine if the current thread is the engine thread:
private void ProcessData(ExternalData data)
{
if (Engine.IsEngineThread)
{
// Already on engine thread - safe to modify entities
UpdateEntity(data);
}
else
{
// On external thread - must queue write operations to engine thread
Engine.QueueUpdate(() => UpdateEntity(data));
}
}This check is required for write operations (create, update, delete entities) and when using the TransactionManager. Entity cache reads with GetEntity(guid, query: false) are thread-safe and do not require queueing. However, GetEntity(guid) with default behavior may trigger server I/O if the entity is not cached.
Since QueueUpdate returns immediately without waiting, exceptions thrown inside the queued action do not propagate to the calling code. Handle exceptions within the action itself:
Engine.QueueUpdate(() =>
{
try
{
var entity = Engine.GetEntity<CustomEntity>(entityGuid);
entity.RunningState = State.Running;
}
catch (Exception ex)
{
Logger.TraceError(ex, "Failed to update entity");
}
});Since QueueUpdateAndWait waits for completion, exceptions propagate to the caller:
try
{
Engine.QueueUpdateAndWait(() =>
{
var entity = Engine.GetEntity<CustomEntity>(entityGuid);
entity.RunningState = State.Running;
});
}
catch (SdkException ex)
{
Logger.TraceError(ex, "Operation failed");
}The engine thread does not have a System.Threading.SynchronizationContext. This means that after an await, the continuation will not return to the engine thread automatically.
// WRONG - continuation runs on thread pool, not engine thread
private async void OnPluginLoaded()
{
var data = await ExternalApi.GetDataAsync();
ProcessData(data); // Runs on wrong thread!
}
// CORRECT - queue entity updates back to engine thread
protected override void OnPluginLoaded()
{
Task.Run(async () =>
{
var data = await ExternalApi.GetDataAsync();
Engine.QueueUpdate(() => ProcessData(data));
});
}- Plugin SDK Lifecycle - When lifecycle methods are called
- Plugin SDK Events - Event handler threading
- Plugin SDK Request Manager - Request handler threading
- SDK Transactions - Transaction usage with threading
-
Security Center SDK Developer Guide Overview of the SDK framework and how to build integrations with Security Center.
-
Platform SDK
- Platform SDK Overview Introduction to the Platform SDK and core concepts.
- SDK Certificates Details certificates, licensing, and connection validation.
- Entity Guide Explains the core entity model, inheritance, and how to work with entities.
- Entity Cache Guide Describes the engine's local entity cache and synchronization.
- SDK Transactions Covers batching operations for performance and consistency.
- ReportManager Querying entities and activity data from Security Center.
- Events and Actions Subscribing to events and handling actions.
- Logging with the Genetec SDK How to configure logging, diagnostics, and debug methods.
- Referencing SDK Assemblies Best practices for referencing assemblies and resolving them at runtime.
- SDK Compatibility Guide Understanding backward compatibility and versioning in the SDK.
-
Plugin SDK
- Plugin SDK Overview Introduction to plugin architecture and capabilities.
- Plugin SDK Certificates SDK certificate requirements for plugin roles.
- Plugin SDK Lifecycle Initialization and disposal patterns.
- Plugin SDK Threading Threading model, QueueUpdate, and async patterns.
- Plugin SDK Configuration Configuration storage and monitoring.
- Plugin SDK Restricted Configuration Secure credential storage and admin-only configuration.
- Plugin SDK Database Database integration and schema management.
- Plugin SDK Events Event subscription and handling.
- Plugin SDK Queries Query processing and response handling.
- Plugin SDK Request Manager Request/response communication with clients.
- Plugin SDK Entity Ownership Understanding plugin-owned entities, running state management, and ownership release.
- Plugin SDK Entity Mappings Using EntityMappings for plugin-specific configuration and external system integration.
- Plugin SDK State Management Reporting plugin health and diagnostics.
- Plugin SDK Server Management High availability and server failover.
- Custom Privileges Defining and enforcing custom privileges.
- Resolving Non-SDK Assemblies Handling third-party dependencies in plugins and workspace modules.
- Deploying Plugins Registering and deploying plugins and workspace modules.
-
Workspace SDK
- Workspace SDK Overview Introduction to client-side UI extensions for Security Desk and Config Tool.
- Creating Modules Module lifecycle, registration patterns, and assembly resolution.
- Tasks and Pages Menu items, page content, and navigation.
- Components Dashboard widgets, tiles, maps, credentials, and content builders.
- Tile Extensions Custom tile widgets, views, and properties panels.
- Services Built-in services for dialogs, maps, alarms, badges, and more.
- Contextual Actions Right-click context menu extensions.
- Options Extensions Custom settings pages in application preferences.
- Monitors Multi-monitor support and shared components.
- Commands Command execution, evaluation, and interception.
- Extending Events Adding custom fields to Security Center events.
- Map Extensions Custom map objects, layers, and providers.
- Timeline Providers Custom timeline event sources for video playback.
-
Macro SDK
- Macro SDK Overview How macros work, creating and configuring macro entities, automation, and monitoring.
- Macro SDK Developer Guide Developing macro code with the UserMacro class and Security Center SDK.
-
- Getting Started Setup, authentication, and basic configuration for the Web SDK.
- Referencing Entities Entity discovery, search capabilities, and parameter formats.
- Entity Operations CRUD operations, multi-value fields, and method execution.
- Partitions Managing partitions, entity membership, and user access control.
- Custom Fields Creating, reading, writing, and filtering custom entity fields.
- Custom Card Formats Managing custom credential card format definitions.
- Actions Control operations for doors, cameras, macros, and notifications.
- Events and Alarms Real-time event monitoring, alarm monitoring, and custom events.
- Incidents Incident management, creation, and attachment handling.
- Reports Activity reports, entity queries, and historical data retrieval.
- Performance Guide Optimization tips and best practices for efficient API usage.
- Reference Entity GUIDs, EntityType enumeration, and EventType enumeration.
- Under the Hood Technical architecture, query reflection, and SDK internals.
- Troubleshooting Common error resolution and debugging techniques.
- Media Gateway Guide Setup and configuration of the Media Gateway role for video streaming.
- Web Player Guide Complete guide to integrating GWP for live and playback video streaming.
- Web Player API Reference Full API documentation with interfaces, methods, properties, and events.
- Web Player Sample Application Comprehensive demo showcasing all GWP features with timeline and PTZ controls.
- Genetec Web Player Multiplexing Sample Multi-camera grid demo using a shared WebSocket connection.