Skip to content

deploy

Redmine-driven deployments dispatched to WebSocket agents, with durable notification queues and a live dashboard.

deploy is a small deployment-orchestration server. A central Vert.x process accepts WebSocket agents running on target hosts and dispatches shell commands to them. Deployments are driven from Redmine issues: an issue is validated by a script, its GitLab diff is posted back as a comment (and to Telegram), the referenced deploy alias is executed across agents, and the issue status is moved Accepted → Processing → Done/Failed. Outbound Redmine and Telegram calls go through durable, at-least-once disk queues with dead-lettering. The server exposes Prometheus metrics, a JSON status endpoint, and a live htmx/SSE dashboard.

flowchart LR
    subgraph producers [Issue producers]
        cb[Redmine webhook<br/>REDMINE_CALLBACK_URI]
        dash[Dashboard POST /issue]
        cmd["?command=issue"]
    end
    producers --> q[[pending issues queue]]
    q --> proc[redmine-processing thread]
    proc --> val{Nashorn<br/>ISSUE_VALIDATION_SCRIPT}
    val -- valid --> diff[GitLab diff] --> deploy
    val -- invalid --> skip[skip]
    diff --> redmine[(Redmine status + comment)]
    diff --> tg[(Telegram)]
    deploy[DeployService.runTask] -->|WebSocket| agents[Agents on target hosts]
    deploy -->|agent id = localhost| local[in-process agent]
    redmine & tg -.-> spool[(durable spools<br/>QUEUE_DIR, dead-letter)]

    subgraph obs [Observability]
        m[/metrics/]
        s[/deploy/status/]
        d[/deploy/dashboard/]
    end
  • Server ↔ agents — agents open a WebSocket to SERVER_BASE_URL + AGENT_ID; the server keys each connection by the last path segment of the URL. A deploy Task is a list of commands, each targeting one or more agent ids; the special id localhost runs in-process on the server.
  • Redmine flow — issues enter a bounded in-memory queue (webhook callback, dashboard, or ?command=issue), are validated by a Nashorn script, diffed against GitLab, deployed, and their status is updated. All Redmine mutations and Telegram messages are enqueued to disk first (QUEUE_DIR) and retried with backoff; poison operations move to a dead/ sub-directory.

Write commands

What a command is and the bundled helper CLIs.

Module Purpose
util IStartupConfig marker for env-driven config.
commands Standalone CLI helper commands run by agents (runner, check-version, wait-url).
agent-api Wire contract between server and agent (messages, AgentCommand).
server-api Server-side domain contract (IDeployService, Task, listeners).
agent Agent runtime: executes shell commands via ProcessBuilder.
server Transport-agnostic core: DeployServiceImpl, alias parsing, local agent.
client-redmine Redmine/GitLab/Telegram integration + durable queues (PersistentSpool).
server-vertx Vert.x runtime and entry point; HTTP routing, dashboard/status/metrics.
agent-websocket WebSocket agent entry point.
integration-test End-to-end tests wiring the server and a WebSocket agent.