Skip to content

Repository files navigation

QueryPush 🛢⚡🌐

Cross-platform database query scheduler that executes database queries on a schedule and sends the records one at a time or in batches to the specified HTTP endpoints with comprehensive retry logic, alerting, and state management.

Features

  • Multi-Database Support: Native providers (SQL Server, MySQL, PostgreSQL, Oracle, SQLite) or ODBC for other databases
  • Cron Scheduling: Standard cron expressions with NCrontab
  • HTTP Integration: Configurable endpoints with headers and multiple HTTP methods
  • Template Variables: Dynamic query parameters with formatting and offsets
  • Retry Logic: Exponential backoff and delay strategies
  • Alert System: Slack and Email notifications with throttling
  • State Persistence: Last run tracking and alert cooldown management
  • Cross-Platform: Windows Service, Linux Systemd, or console mode
  • Configuration Validation: Startup validation with detailed error messages
  • Hot Reload: JSON configuration changes without restart

Getting Started

Prerequisites

QueryPush supports both native database providers and ODBC for database connectivity.

Native Providers (Recommended) Native providers are built into QueryPush and require no additional driver installation:

  • SQL Server (sqlserver)
  • MySQL (mysql)
  • PostgreSQL (postgres or postgresql)
  • Oracle (oracle)
  • SQLite (sqlite)

ODBC Provider For databases without native support, use the ODBC provider. ODBC drivers must be installed on each target system:

ODBC Installation notes:

  • Drivers are platform-specific (Windows/Linux/macOS)
  • Must match your system architecture (x64/x86)
  • Required on every machine where QueryPush runs
  • Driver versions may affect connection string syntax

Quick Start

  1. Download your platform-specific binary version from the releases tab
  2. If using ODBC, install the required drivers for your databases
  3. Configure appsettings.json with connection strings for databases, the queries to execute, and the endpoints to send the data to (examples below)
  4. Run QueryPush.exe at the command line or deploy it as a background service to continuously run

Cross-Platform Deployment

Console Mode (All Platforms)

dotnet run
# or
./QueryPush

Windows Service

QueryPush.exe --service
# Install using provided script:
install-windows.bat

Linux Systemd Service

./QueryPush --service
# Install using provided script:
./install-linux.sh

macOS (Console Mode)

./QueryPush

Configuration Reference

QueryPush uses appsettings.json for all configuration. Below is a comprehensive reference of all available options:

Database Configuration

PropertyTypeRequiredDefaultDescription
databases[].namestringUnique database identifier
databases[].providerenumodbcDatabase provider: odbc, sqlserver, mysql, oracle, postgres/postgresql, sqlite
databases[].connectionStringstringProvider-specific connection string

Endpoint Configuration

PropertyTypeRequiredDefaultDescription
endpoints[].namestringUnique endpoint identifier
endpoints[].methodenumPOSTHTTP method: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS
endpoints[].urlstringTarget HTTP endpoint URL
endpoints[].headers[].namestringHTTP header name
endpoints[].headers[].valuestringHTTP header value
endpoints[].retryAttemptsinteger3Max retry attempts (0-10)
endpoints[].retryStrategyenumDelayRetry strategy: Delay, ExponentialBackoff
endpoints[].backOffSecondsinteger15Base delay between retries (1-300)
endpoints[].sendRequestIfNoResultsbooleanfalseSend HTTP request even with no data
endpoints[].payloadSizeintegerint.MaxValueRecords per HTTP request (1-∞)
endpoints[].requestDelayinteger500Milliseconds between requests (0-10000)

Alert Configuration

PropertyTypeRequiredDefaultDescription
alerts.slack.defaultbooleanfalseUse as default alert method
alerts.slack.webhookUrlstringSlack webhook URL
alerts.slack.channelstring#alertsSlack channel
alerts.slack.usernamestringQueryPushBot username
alerts.slack.alertCooldownMinutesinteger60Minutes between alerts (1-1440)
alerts.email.smtpHoststringSMTP server hostname
alerts.email.smtpPortinteger587SMTP server port (1-65535)
alerts.email.useSslbooleantrueEnable SSL/TLS
alerts.email.fromstringSender email address
alerts.email.tostringRecipient email address
alerts.email.usernamestringSMTP authentication username
alerts.email.passwordstringSMTP authentication password
alerts.email.alertCooldownMinutesinteger60Minutes between alerts (1-1440)

Logging Configuration

PropertyTypeRequiredDefaultDescription
logging.rotationStrategyenumDailyLog rotation: Daily, Weekly, Monthly, Never
logging.retentionDaysinteger30Days to retain logs (1-365)
logging.logDirectorystringlogsLog file directory path

Query Configuration

PropertyTypeRequiredDefaultDescription
queries[].namestringUnique query identifier
queries[].cronstringStandard cron expression (Quartz Cron Generator)
queries[].databasestringReference to database name
queries[].endpointstringReference to endpoint name
queries[].enabledbooleantrueEnable/disable query
queries[].runOnStartupbooleantrueExecute immediately on startup
queries[].timeoutSecondsinteger30Query timeout (1-3600)
queries[].maxRowsintegerint.MaxValueMaximum rows to process (1-∞)
queries[].payloadFormatenumJsonArrayData format: JsonArray, JsonLines
queries[].onFailureenumLogAndContinueFailure action: LogAndContinue, Halt, SlackAlert, EmailAlert
queries[].queryTextstring✓*Inline SQL query text
queries[].queryFilestring✓*Path to external query file

*Either queryText or queryFile is required

Template Variables

QueryPush supports dynamic variables in query text:

VariableDescriptionExample Output
{DateTimeNow}Current local datetime2024-01-15 14:30:25
{UtcNow}Current UTC datetime2024-01-15 19:30:25
{DateNow}Current date only2024-01-15
{LastRun}Last successful execution2024-01-15 14:29:25
{Guid}New GUID550e8400-e29b-41d4-a716-446655440000
{MachineName}Host machine nameSERVER01
{Env:VARIABLE}Environment variableProduction

Advanced Formatting

Variables support offset and formatting:

  • Offset: {DateNow\|-1:00:00\|yyyy-MM-dd} → Yesterday's date
  • Format Only: {DateTimeNow\|yyyy-MM-dd HH:mm:ss} → Custom format
  • Offset + Format: {UtcNow\|+05:00:00\|yyyy-MM-dd} → 5 hours ahead

How Scheduling Works

  1. QuartzSchedulerService initializes Quartz.NET scheduler at startup
  2. Each enabled query gets a dedicated Quartz job with its cron expression
  3. Jobs execute independently when their cron schedule triggers
  4. QueryJob handles individual query execution with correlation tracking
  5. Results are processed, chunked, and sent to configured HTTP endpoints
  6. State tracking prevents duplicate executions and manages alert cooldowns
  7. Configuration changes trigger automatic rescheduling of all jobs

Safety Features

  • Concurrent Execution Protection: Each query is protected by [DisallowConcurrentExecution] - if a query is still running when its next scheduled time arrives, the new execution is skipped
  • State Persistence: Last run timestamps prevent duplicate executions across application restarts
  • Database Connection Validation: The DatabaseConnectionFactory validates connections at startup with detailed error messages for unsupported providers or connection failures
  • Configuration Validation: Comprehensive validation of all settings, references, and file paths before execution begins

State Management

QueryPush maintains state in QueryState.json:

  • Last run timestamps per query (prevents duplicate execution)
  • Alert timestamps per query/type (implements cooldown throttling)
  • Storage location: Stored in the same directory as the application executable

Example Configuration (Minimal)

Here is an example of a configuration with a single database query that runs daily at 9:00 AM using native SQL Server provider:

{
"databases": [
{
"name": "MyDb",
"provider": "sqlserver",
"connectionString": "Server=localhost;Database=MyApp;Integrated Security=true;"
}
],
"endpoints": [
{
"name": "MyWebhook",
"url": "https://webhook.site/your-unique-url"
}
],
"queries": [
{
"name": "Daily Report",
"cron": "0 0 9 * * ?",
"database": "MyDb",
"endpoint": "MyWebhook",
"queryText": "SELECT * FROM Users WHERE CreatedDate >= '{DateNow|-1:00:00|yyyy-MM-dd}'"
}
]
}

Example Configuration

{
"databases": [
{
"name": "MainDb",
"provider": "sqlserver",
"connectionString": "Server=localhost;Database=MyApp;Integrated Security=true;"
},
{
"name": "AnalyticsDb",
"provider": "postgres",
"connectionString": "Host=analytics.example.com;Database=analytics;Username=readonly;Password=secret;"
}
],
"endpoints": [
{
"name": "SyncAPI",
"method": "POST",
"url": "https://api.example.com/sync",
"retryAttempts": 3,
"retryStrategy": "Delay",
"backOffSeconds": 15,
"sendRequestIfNoResults": false,
"payloadSize": 100,
"requestDelay": 500,
"headers": [
{
"name": "Authorization",
"value": "Bearer {Env:API_TOKEN}"
}
]
}
],
"alerts": {
"slack": {
"default": true,
"webhookUrl": "https://hooks.slack.com/services/...",
"channel": "#alerts"
}
},
"queries": [
{
"name": "Daily User Sync",
"cron": "0 0 6 * * ?",
"database": "MainDb",
"endpoint": "SyncAPI",
"onFailure": "SlackAlert",
"queryText": "SELECT Id, Email, CreatedAt FROM Users WHERE CreatedAt >= '{DateNow|-1:00:00|yyyy-MM-dd}'"
}
]
}

Logging

  • Console: All platforms
  • Windows Event Log: When running as service (Application log, source QueryPush)
  • Linux Journal: Automatic via systemd integration
  • Configuration validation: Detailed startup error messages

Build & Publish

# Development build
dotnet build
# Platform-specific releases
dotnet publish -r win-x64 --self-contained -c Release
dotnet publish -r linux-x64 --self-contained -c Release
dotnet publish -r osx-x64 --self-contained -c Release

About

QueryPush is a lightweight tool that runs scheduled database queries and pushes the results to remote APIs - designed for incremental data syncs, cron scheduling, and flexible endpoint integration.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages