@dawntech/dispatcher
v0.2.8
Published
A TypeScript Node.js package for sending push messages in conversational chatbots on the Blip platform.
Downloads
582
Readme
dwn-dispatcher
A TypeScript Node.js package for sending push messages in conversational chatbots on the Blip platform. Provides a robust, multi-instance compliant system with automatic retries, scheduling, and shift-based time windows.
Features
- Channel-agnostic message dispatching (WhatsApp, Google Business Messages, etc.)
- Asynchronous message delivery with status monitoring
- Automatic retries with exponential backoff
- Multi-instance deployment support with distributed locking
- Shift-aware scheduling with timezone support
- Template-based messaging with payload filling
- Event publishing for monitoring and analytics
Installation
# npm
npm install @dawntech/dispatcher
# yarn
yarn add @dawntech/dispatcher
# pnpm
pnpm add @dawntech/dispatcherUsage
Basic Example
import { Dispatcher, Descriptor } from '@dawntech/dispatcher';
// 1. Setup Infrastructure
const redisUrl = process.env.REDIS_URL || 'redis://localhost:6379';
const connection = {
contract: 'my-blip-contract',
key: 'my-blip-api-key',
};
const dispatcher = new Dispatcher('my-dispatcher-1', redisUrl, connection);
await dispatcher.setup();Dispatcher ID Convention
The dispatcher ID supports the : character as a namespace separator. Redis tools (such as Redis Commander and Redis Insight) interpret : as a folder delimiter, creating a navigable tree structure for keys.
Use this convention to organize dispatchers hierarchically:
// Flat ID
const dispatcher = new Dispatcher('main', redisUrl, connection);
// Keys: dwn-dispatcher:main:message:..., dwn-dispatcher:main:queue:..., etc.
// Namespaced ID
const dispatcher = new Dispatcher('acme:onboarding', redisUrl, connection);
// Keys: dwn-dispatcher:acme:onboarding:message:..., dwn-dispatcher:acme:onboarding:queue:..., etc.This results in the following folder structure in Redis GUI tools:
dwn-dispatcher:
├── acme:
│ └── onboarding:
│ ├── manifest ← created on setup
│ ├── message:...
│ ├── index:...
│ ├── queue:...
│ └── metrics:...
└── main:
├── manifest
├── message:...
├── index:...
├── queue:...
└── metrics:...Every dispatcher creates a manifest key (Redis hash) on setup() containing metadata such as the package version and timestamps. This key is used to validate that a dispatcher actually exists.
// 2. Define a Descriptor (Message content + Event listeners)
const welcomeDescriptor = new Descriptor('welcome_message', (payload) => ({
type: 'text/plain',
content: `Welcome ${payload.name}!`,
}));
// Optional: listen to events for this specific message
welcomeDescriptor.on('delivered', (msg) => {
console.log(`Message ${msg.messageId} was delivered!`);
});
// 3. Send message
await dispatcher.send(welcomeDescriptor, '[email protected]', {
name: 'John Doe',
});With Scheduling
await dispatcher.send('[email protected]', welcomeDescriptor, payload, {
schedule: '2024-01-15T14:00:00Z',
});With Shift Restrictions
await dispatcher.send('[email protected]', welcomeDescriptor, payload, {
shifts: [
{
days: 31, // Mon-Fri (bitmask)
start: '09:00',
end: '18:00',
gmt: '-3',
},
],
});Monitoring
You can monitor the Dispatcher metrics and receive alerts for failures or high load using DispatcherMonitor.
import { Dispatcher, DispatcherMonitor } from '@dawntech/dispatcher';
// 1. Create Dispatcher
const dispatcher = new Dispatcher('my-dispatcher', redisUrl, connection);
await dispatcher.setup();
// 2. Create Monitor attached to Dispatcher
const monitor = new DispatcherMonitor(dispatcher, {
interval: 60000, // Check every minute
rules: [
{
type: 'failure_rate',
threshold: 0.05, // 5% failure rate
window: 60000 * 60, // 1 hour window
debounce: 30 * 60000, // Alert at most every 30 mins
},
{
type: 'queue_size',
threshold: 1000, // Alert if > 1000 messages pending/scheduled
debounce: 10 * 60000, // Alert at most every 10 mins
},
],
});
// 3. Listen for Alerts
monitor.on('alert', (alert) => {
console.error(`[ALERT] ${alert.type}: ${alert.message}`, alert.details);
// Send to external monitoring (e.g., Slack, PagerDuty, Datadog)
});
monitor.on('resolved', (alert) => {
console.log(`[RESOLVED] ${alert.type}: ${alert.message}`);
});
// 4. Start Monitoring
monitor.start();
// ... application runs ...
// 5. Cleanup
monitor.stop();Development Quick Start
Prerequisites
- Node.js >= 24.0.0
- npm >= 10.0.0
- Docker and Docker Compose (for local development)
- Blip Platform account with API credentials
Setup Local Environment
Run the setup script to install dependencies and start infrastructure:
npm run setupThis script will:
- Check prerequisites (Docker, Node.js)
- Create
.envfile from.env.example - Install npm dependencies
- Start Redis container
- Display available commands
Manual Setup
If you prefer to set up manually:
- Copy environment file
cp .env.example .env- Update
.envwith your Blip credentials
BLIP_CONTRACT=your-contract-id
BLIP_API_KEY=your-api-key- Install dependencies
npm install- Start Docker services
npm run docker:upAvailable Commands
Development
npm run dev- Start development with auto-reloadnpm run build- Build TypeScript to JavaScriptnpm run setup- Initial project setup (prerequisites check, install, docker up)npm run clean- Remove build artifacts
Testing & Examples
npm run test- Run unit tests (Jest)npm run test:basic- Integration test: Basic message sendingnpm run test:contact- Integration test: Contact metadata updatenpm run test:schedule- Integration test: Message schedulingnpm run test:status-config- Integration test: Custom final status (READ)npm run test:intent- Integration test: Message intent with extra fields
Docker
npm run docker:up- Start Redis containernpm run docker:down- Stop all containersnpm run docker:logs- View container logsnpm run docker:redis-cli- Open Redis CLInpm run docker:clean- Stop containers and remove volumesnpm run docker:restart- Restart all containersnpm run docker:tools- Start Redis GUI tools (Commander & Insight)
Infrastructure
Redis
- URL:
redis://localhost:6379 - Purpose: Primary storage for dispatcher repository and event transport
- Persistence: Volume-backed with AOF enabled
Optional GUI Tools
Start Redis management tools:
npm run docker:tools- Redis Commander: http://localhost:8081 - Web-based Redis management
- Redis Insight: http://localhost:8001 - Advanced Redis GUI
Project Structure
src/
├── core/
│ ├── BlipAPI.ts # Blip API client
│ ├── Dispatcher.ts # Main orchestrator (lifecycle & scheduling)
│ ├── Descriptor.ts # Message content & event handling
│ └── MessageTemplate.ts # Template base class (legacy/base)
├── repositories/
│ ├── Repository.ts # Storage layer base interface
│ ├── RedisRepository.ts # Shared storage (Redis)
│ └── LocalRepository.ts # In-memory storage (Local)
├── types/
│ └── index.ts # TypeScript types
└── index.ts # Main entry pointBuild
Build the TypeScript code:
npm run buildOutput will be in the dist/ directory with:
- Compiled JavaScript files
- TypeScript declaration files (
.d.ts) - Source maps
Testing
npm testEnvironment Variables
See .env.example for all available configuration options:
- REDIS_URL: Redis connection URL
- BLIP_CONTRACT: Blip contract identifier
- BLIP_API_KEY: Blip API key
- MAX_RETRIES: Maximum retry attempts (default: 0)
- LOCK_TTL: Distributed lock timeout in ms (default: 30000)
- POLLING_INTERVAL: Background polling interval in ms (default: 5000)
