Background Commands
Hosanna implements a robust system for handling background commands and asynchronous operations through its AsyncCommand framework. This documentation explains how background commands work and how to use them effectively in your application.
Live Example
Dispatch a background command and watch the UI handle progress and completion.
Core Components
1. AsyncCommand
The AsyncCommand class is the fundamental building block for background operations in Hosanna. It provides:
- Unique command identification
- Lifecycle management (dispatch, cancel, pause, resume)
- Progress tracking
- State management
- Promise-based execution
2. Command Structure
Each background command consists of:
-
ID: A unique identifier for tracking
-
Scope: The command's operational context
-
Handler: The specific operation handler
-
Arguments: Optional parameters for the command
-
State: Current execution state
-
Progress: Completion progress (0.0 to 1.0)
Using Background Commands
1. Creating a Command Handler
@commandCategory('DataLoader')
class LoadDataHandler {
@command('LoadJsonData')
loadJsonData(payload: any): HsPromise<any> {
// Implement async operation
}
}
2. Dispatching Commands
You can dispatch background commands from views using:
this.dispatchAsync('DataLoader', 'LoadJsonData', { url: '/data.json' })
.then((result) => {
// Handle success
})
.catch((error) => {
// Handle error
});
Passing function pointers across tasks
Sometimes you need to pass a function to be executed in a background task. Use AsyncFunctionPointer
(module + export name) to reference the function safely across node/task boundaries.
import { processRows } from './transformFunctions';
this.dispatch<IHsFetchResponse>(Http.Get, {
url: 'https://api.example.com/data',
transformFunction: processRows
});
Signature:
// hosanna-api
type AsyncFunctionPointer = Function;
The runtime can retrieve the function later (e.g., via a helper like getAsyncFunctionFromPointer
) and execute it inside a task, avoiding closure capture issues.
Command Lifecycle
Background commands go through several states:
- Initializing: Command is being created
- Running: Command is actively executing
- Paused: Command execution is temporarily suspended
- Completed: Command has finished successfully
- Failed: Command encountered an error
- Cancelled: Command was manually cancelled
Integration with Async Framework
Hosanna's background commands integrate with:
- AsyncManager: Central controller for async tasks
- HsPromise: Custom promise implementation
- TimerService: Manages timing and scheduling
- PortPromise: Platform-specific promise implementation (e.g., for Roku)
Best Practices
-
Error Handling
- Always implement proper error handling in command handlers
- Use try/catch blocks for potential failures
- Provide meaningful error messages
-
Progress Tracking
- Update progress for long-running operations
- Use progress callbacks for UI updates
-
Resource Management
- Properly clean up resources when commands complete
- Cancel long-running commands when no longer needed
-
Platform Considerations
- Use platform-specific implementations when necessary
- Consider memory constraints on different devices
Example Implementation
// Define a background command handler
@commandCategory('MediaLoader')
class MediaLoadHandler {
@command('LoadVideo')
async loadVideo(payload: {url: string}): HsPromise<void> {
try {
// Initialize progress
this.progress = 0;
// Perform async operation
const result = await fetch(payload.url);
// Update progress
this.progress = 0.5;
// Process result
const videoData = await result.json();
// Complete operation
this.progress = 1.0;
return videoData;
} catch (error) {
throw new Error(`Failed to load video: ${error.message}`);
}
}
}
// Using the command in a view
class VideoPlayerView extends BaseView {
loadVideo(url: string) {
this.dispatchAsync('MediaLoader', 'LoadVideo', { url })
.then(videoData => this.playVideo(videoData))
.catch(error => this.handleError(error));
}
}
Debugging Background Commands
For debugging background commands, Hosanna provides:
- Command execution logging
- State tracking
- Progress monitoring
- Error reporting
You can use the Remote Debug Panel to monitor and debug background commands during development.