Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ DrasiServer separates two independent concepts:
- Config file is not writable (file permissions prevent writing)

**Important distinction:**
- `persist_config: false` → API mutations are allowed but NOT saved to config file
- `persistConfig: false` → API mutations are allowed but NOT saved to config file
- Read-only config file → API mutations are blocked entirely
- This allows dynamic query creation without persistence (useful for programmatic usage)

Expand Down
29 changes: 21 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Drasi Server

Drasi Server is a standalone server for the [Drasi](https://drasi.io) data change processing platform. It wraps the [DrasiLib](https://github.com/drasi-project/drasi-lib) library with enterprise-ready features including a REST API, YAML-based configuration, and production lifecycle management.
Drasi Server is a standalone server for the [Drasi](https://drasi.io) data change processing platform. It wraps the [DrasiLib](https://github.com/drasi-project/drasi-core/tree/main/lib) library with enterprise-ready features including a REST API, YAML-based configuration, and production lifecycle management.

## What is Drasi?

Expand Down Expand Up @@ -284,7 +284,7 @@ sources:
password: ${DB_PASSWORD}
tables: [orders, customers]
slotName: drasi_slot
publicationName: drasi_pub
publicationName: drasi_publication
sslMode: prefer
tableKeys:
- table: orders
Expand Down Expand Up @@ -362,7 +362,7 @@ sources:

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `dataType` | string | `generic` | Type of mock data to generate |
| `dataType` | string | `generic` | Type of mock data: `sensor` (SensorReading nodes), `counter` (Counter nodes), `generic` (Generic nodes) |
| `intervalMs` | integer | `5000` | Data generation interval in milliseconds |

#### Platform Source (`platform`)
Expand Down Expand Up @@ -465,7 +465,7 @@ queries:
| `query` | string | (required) | Query string (Cypher or GQL) |
| `queryLanguage` | string | `GQL` | Query language: `Cypher` or `GQL` |
| `sources` | array | (required) | Source subscriptions |
| `autoStart` | boolean | `true` | Start query automatically |
| `autoStart` | boolean | `false` | Start query automatically |
| `enableBootstrap` | boolean | `true` | Process initial data from sources |
| `bootstrapBufferSize` | integer | `10000` | Event buffer size during bootstrap |
| `priorityQueueCapacity` | integer | (global) | Override queue capacity for this query |
Expand Down Expand Up @@ -621,6 +621,7 @@ reactions:
| `maxRetries` | integer | `3` | Maximum retry attempts |
| `connectionRetryAttempts` | integer | `5` | Connection retry attempts |
| `initialConnectionTimeoutMs` | integer | `10000` | Initial connection timeout |
| `metadata` | object | `{}` | Custom gRPC metadata key-value pairs |

#### gRPC Adaptive Reaction (`grpc-adaptive`)

Expand All @@ -636,6 +637,19 @@ reactions:
adaptiveMaxBatchSize: 1000
```

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `endpoint` | string | `grpc://localhost:50052` | gRPC endpoint URL |
| `timeoutMs` | integer | `5000` | Connection timeout in milliseconds |
| `maxRetries` | integer | `3` | Maximum retry attempts |
| `connectionRetryAttempts` | integer | `5` | Connection retry attempts |
| `initialConnectionTimeoutMs` | integer | `10000` | Initial connection timeout |
| `metadata` | object | `{}` | Custom gRPC metadata key-value pairs |
| `adaptiveMinBatchSize` | integer | `1` | Minimum batch size |
| `adaptiveMaxBatchSize` | integer | `1000` | Maximum batch size |
| `adaptiveWindowSize` | integer | `100` | Window size for adaptive calculations |
| `adaptiveBatchTimeoutMs` | integer | `1000` | Batch timeout in milliseconds |

#### SSE Reaction (`sse`)

Streams query results via Server-Sent Events.
Expand Down Expand Up @@ -941,11 +955,10 @@ Apache License 2.0. See [LICENSE](LICENSE) for details.

## Related Projects

- [DrasiLib](https://github.com/drasi-project/drasi-lib) - Core event processing engine
- [Drasi](https://github.com/drasi-project/drasi) - Main Drasi project
- [Drasi Documentation](https://drasi.io/docs) - Complete documentation
- [DrasiLib](https://github.com/drasi-project/drasi-core/tree/main/lib) - Core event processing engine
- [Drasi](https://github.com/drasi-project) - Main Drasi project
- [Drasi Documentation](https://drasi.io/) - Complete documentation

## Support

- **Issues**: [GitHub Issues](https://github.com/drasi-project/drasi-server/issues)
- **Discussions**: [GitHub Discussions](https://github.com/drasi-project/drasi/discussions)
21 changes: 10 additions & 11 deletions config/server-with-env-vars.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,9 @@ sources:
# Optional: SSL configuration
# ssl_mode: "${DB_SSL_MODE:-prefer}"

# Bootstrap provider uses the parent source's connection details
bootstrapProvider:
kind: postgres
host: "${DB_HOST}"
port: "${DB_PORT:-5432}"
database: "${DB_NAME}"
user: "${DB_USER}"
password: "${DB_PASSWORD}"

# HTTP source for receiving events
- kind: http
Expand Down Expand Up @@ -83,7 +79,6 @@ reactions:
queries:
- high-value-orders
autoStart: true
logLevel: "${REACTION_LOG_LEVEL:-info}"

# HTTP webhook reaction
- kind: http
Expand All @@ -94,12 +89,16 @@ reactions:

# Webhook URL - uses environment variable
baseUrl: "${WEBHOOK_URL}"
# Optional: Authentication token
# token: "${API_TOKEN}"

# Optional: Authentication
# headers:
# Authorization: "Bearer ${API_TOKEN}"

method: POST
# Routes define per-query endpoints
routes:
high-value-orders:
added:
url: "/notifications/high-value"
method: "POST"
body: '{"orderId": "{{after.order_id}}", "total": {{after.total}}}'

# Server-Sent Events (SSE) for real-time updates
- kind: sse
Expand Down
2 changes: 1 addition & 1 deletion examples/configs/02-sources/grpc-streaming-source.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
# - host: Address to bind (default: 0.0.0.0)
# - port: Port to listen on (default: 50051)
# - endpoint: Custom endpoint (optional)
# - timeout_ms: Request timeout in milliseconds (default: 5000)
# - timeoutMs: Request timeout in milliseconds (default: 5000)
#
# Run with: cargo run -- --config examples/configs/02-sources/grpc-streaming-source.yaml
#
Expand Down
2 changes: 1 addition & 1 deletion examples/configs/02-sources/http-webhook-receiver.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
# - host: Address to bind (default: 0.0.0.0)
# - port: Port to listen on (required)
# - endpoint: Custom endpoint path (optional)
# - timeout_ms: Request timeout in milliseconds (default: 10000)
# - timeoutMs: Request timeout in milliseconds (default: 10000)
#
# Run with: cargo run -- --config examples/configs/02-sources/http-webhook-receiver.yaml
#
Expand Down
12 changes: 6 additions & 6 deletions examples/configs/03-reactions/grpc-streaming-reaction.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
#
# Configuration options:
# - endpoint: gRPC endpoint URL (default: grpc://localhost:50052)
# - timeout_ms: Request timeout (default: 5000)
# - batch_size: Number of events per batch (default: 100)
# - batch_flush_timeout_ms: Max wait before flushing batch (default: 1000)
# - max_retries: Retry attempts for failed sends (default: 3)
# - connection_retry_attempts: Connection retry attempts (default: 5)
# - initial_connection_timeout_ms: Initial connection timeout (default: 10000)
# - timeoutMs: Request timeout (default: 5000)
# - batchSize: Number of events per batch (default: 100)
# - batchFlushTimeoutMs: Max wait before flushing batch (default: 1000)
# - maxRetries: Retry attempts for failed sends (default: 3)
# - connectionRetryAttempts: Connection retry attempts (default: 5)
# - initialConnectionTimeoutMs: Initial connection timeout (default: 10000)
# - metadata: Custom gRPC metadata headers
#
# Run with: cargo run -- --config examples/configs/03-reactions/grpc-streaming-reaction.yaml
Expand Down
6 changes: 3 additions & 3 deletions examples/configs/03-reactions/http-webhook-sender.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
# - Building event-driven architectures
#
# Configuration options:
# - base_url: Base URL for all requests
# - baseUrl: Base URL for all requests
# - token: Authentication token (added to Authorization header)
# - timeout_ms: Request timeout in milliseconds
# - timeoutMs: Request timeout in milliseconds
# - routes: Per-query endpoint configuration
#
# Each route can specify:
# - url: Endpoint path (appended to base_url)
# - url: Endpoint path (appended to baseUrl)
# - method: HTTP method (GET, POST, PUT, PATCH, DELETE)
# - body: Request body template (Handlebars)
# - headers: Custom HTTP headers
Expand Down
4 changes: 2 additions & 2 deletions examples/configs/03-reactions/profiler-performance.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
# - Performance regression testing
#
# Configuration options:
# - window_size: Number of samples in the observation window (default: 100)
# - report_interval_secs: Seconds between performance reports (default: 60)
# - windowSize: Number of samples in the observation window (default: 100)
# - reportIntervalSecs: Seconds between performance reports (default: 60)
#
# The profiler tracks:
# - Event throughput (events/second)
Expand Down
6 changes: 3 additions & 3 deletions examples/configs/03-reactions/sse-browser-streaming.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
# Configuration options:
# - host: Address to bind (default: 0.0.0.0)
# - port: Port to listen on (default: 8080)
# - sse_path: Event stream endpoint path (default: /events)
# - heartbeat_interval_ms: Keep-alive interval (default: 30000)
# - ssePath: Event stream endpoint path (default: /events)
# - heartbeatIntervalMs: Keep-alive interval (default: 30000)
# - routes: Per-query template configuration
# - default_template: Default template for all queries
# - defaultTemplate: Default template for all queries
#
# Templates can include a 'path' field for multi-endpoint routing.
#
Expand Down
8 changes: 4 additions & 4 deletions examples/configs/05-advanced-features/adaptive-batching.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
# - grpc-adaptive: gRPC reaction with adaptive batching
#
# Adaptive batching parameters:
# - adaptive_min_batch_size: Minimum batch size (default: 1)
# - adaptive_max_batch_size: Maximum batch size (default: 1000)
# - adaptive_window_size: Observation window for rate calculation (default: 100)
# - adaptive_batch_timeout_ms: Max wait before flushing (default: 1000)
# - adaptiveMinBatchSize: Minimum batch size (default: 1)
# - adaptiveMaxBatchSize: Maximum batch size (default: 1000)
# - adaptiveWindowSize: Observation window for rate calculation (default: 100)
# - adaptiveBatchTimeoutMs: Max wait before flushing (default: 1000)
#
# Run with: cargo run -- --config examples/configs/05-advanced-features/adaptive-batching.yaml

Expand Down
2 changes: 1 addition & 1 deletion examples/configs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ sources:
- table: users
keyColumns: [id]
bootstrapProvider: # Load existing data on startup
type: postgres
kind: postgres
```

### Reaction Types
Expand Down
4 changes: 2 additions & 2 deletions examples/getting-started/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ reactions:
- hello-world-from
- message-count
- inactive-people
default_template:
defaultTemplate:
added:
template: "[{{query_name}}] + {{after}}"
updated:
Expand All @@ -285,7 +285,7 @@ Streams results to browser via Server-Sent Events:
- inactive-people
host: 0.0.0.0
port: 8081
sse_path: /events
ssePath: /events
```

## API Reference
Expand Down
2 changes: 1 addition & 1 deletion examples/trading/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,7 @@ const reactionConfig = {
kind: 'sse',
id: 'my-stream',
queries: ['my-query'],
auto_start: true,
autoStart: true,
host: '0.0.0.0',
port: 50051,
ssePath: '/events',
Expand Down
34 changes: 34 additions & 0 deletions tests/example_configs_validation_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ use std::path::Path;
/// List of example config files to validate.
/// These paths are relative to the project root.
const EXAMPLE_CONFIGS: &[&str] = &[
// Top-level config directory (Docker and quick-start templates)
"config/server-minimal.yaml",
"config/server-docker.yaml",
"config/server-with-env-vars.yaml",
// Integration test configs
"tests/integration/getting-started/config.yaml",
// Solution examples
"examples/getting-started/server-config.yaml",
"examples/playground/server/playground.yaml",
Expand Down Expand Up @@ -99,6 +105,34 @@ fn test_all_example_configs_are_valid() {

// Individual tests for each config file provide better granularity in test output

// ==================== Top-level Config Directory ====================

#[test]
fn test_config_server_minimal() {
let path = "config/server-minimal.yaml";
load_config_file(path).unwrap_or_else(|e| panic!("Failed to validate {path}: {e}"));
}

#[test]
fn test_config_server_docker() {
let path = "config/server-docker.yaml";
load_config_file(path).unwrap_or_else(|e| panic!("Failed to validate {path}: {e}"));
}

#[test]
fn test_config_server_with_env_vars() {
let path = "config/server-with-env-vars.yaml";
load_config_file(path).unwrap_or_else(|e| panic!("Failed to validate {path}: {e}"));
}

// ==================== Integration Test Configs ====================

#[test]
fn test_integration_getting_started_config() {
let path = "tests/integration/getting-started/config.yaml";
load_config_file(path).unwrap_or_else(|e| panic!("Failed to validate {path}: {e}"));
}

// ==================== Existing Examples ====================

#[test]
Expand Down
Loading