Repository navigation
Add optional FlowView Query Service backend for parallel queries - #290
Merged
Merged
Conversation
Add a long-running Go service (service/flowview-query) that runs the parallel map-reduce in-process (goroutine worker pool, shared shard cache, background maintenance), selectable under FlowView Settings as the Parallel Query Backend (default Legacy PHP Runner). parallel_database_query_run() dispatches scheduled query ids to the service over localhost (POST /run) instead of forking flowview_runner.php per query/shard; the service reads the same shard tables, honours flowview_parallel_threads and MaxScale, writes results back, and PHP falls back to the legacy runner if the service is unreachable.
Contributor
There was a problem hiding this comment.
🔵 Needs a closer look
The untested database-backed path has unresolved fallback, concurrency, security, and deployment issues.
10 open findings
Reset failed query state before falling back to the legacy runner · New Reject non-loopback listen addresses · New Authenticate state-changing endpoints · New Allow configured remote database endpoints · New Re-select the read pool when MaxScale settings change · New Make self-tests exercise the production map-reduce path · New Use a shared concurrency limiter across all requests · New Normalize time values to SQL datetime strings · New Retain query metadata when intermediary table cleanup fails · New Regenerate the gettext translation template · New
What changed in this PR
Adds an optional Go-based backend for FlowView parallel queries while retaining the legacy PHP runner as the default.
Changes:
- Adds the query service, scheduler, HTTP API, configuration, and systemd deployment assets.
- Integrates backend selection, endpoint discovery, dispatch, and legacy fallback into PHP.
- Documents installation, database permissions, operation, and dependencies.
| File | Description |
|---|---|
setup.php |
Adds query-backend settings. |
includes/functions.php |
Dispatches queries to the service with fallback. |
service/flowview-query/main.go |
Wires service lifecycle and HTTP listener. |
service/flowview-query/config.go |
Loads database and runtime configuration. |
service/flowview-query/types.go |
Defines API and query data structures. |
service/flowview-query/query.go |
Implements map-reduce execution and caching. |
service/flowview-query/scheduler.go |
Performs query and cache maintenance. |
service/flowview-query/server.go |
Implements HTTP endpoints. |
service/flowview-query/demo.go |
Provides the in-memory self-test demonstration. |
service/flowview-query/config.sample.json |
Supplies example service configuration. |
service/flowview-query/flowview-query.service |
Adds the systemd unit. |
service/flowview-query/README.md |
Documents architecture and deployment. |
service/flowview-query/go.mod |
Defines the Go module and dependency. |
service/flowview-query/go.sum |
Records dependency checksums. |
service/flowview-query/.gitignore |
Excludes Go build outputs. |
CHANGELOG.md |
Records the new backend feature. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…ns.php untouched Move the backend switch and the service HTTP helpers out of includes/functions.php (coverage-measured) into flowview_runner.php (the parallel query parent CLI entry) and setup.php (both allowlisted). flowview_runner.php now delegates the whole query to the service when the backend is 'service', eliminating the per-shard PHP worker forks, and falls back to the legacy parent runner otherwise. Allowlist flowview_runner.php as a CLI entry point in patch-coverage.
Security/correctness fixes from the PR review: - shared engine-wide worker limiter (global concurrency cap, context-aware acquire) - dynamic MaxScale read pool honouring the live flowview_use_maxscale setting - normalize time.Time to SQL datetime (and disable DSN parseTime) - token auth (Authorization: Bearer) + enforced POST on state-changing endpoints - refuse to bind a non-loopback listen host - keep the query row when a scheduler map-table DROP fails (retry, no orphan) - drop IPAddressAllow/Deny from the systemd unit so remote DB/MaxScale works - PHP: reset query to a clean pending state before the legacy fallback; send auth token - add flowview_query_service_token setting; regenerate cacti.pot Testing: real sqlmock-based engine/scheduler/server/config tests (replacing the toy selftest for coverage), plus a Go CI workflow (go vet + race tests).
bmfmancini
approved these changes
Oct 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Adds an optional FlowView Query Service — a small long-running Go service
(
service/flowview-query) that runs FlowView's parallel (map-reduce) netflowqueries in-process — and makes it selectable from the FlowView settings page
as the Parallel Query Backend. The default stays the Legacy PHP Runner, so
behaviour is unchanged until an administrator opts in.
Why
Today
parallel_database_query_run()forksflowview_runner.phpper query, andthe parent runner forks another PHP process per shard, then both the caller
and parent poll the coordination tables with
usleep. For small or cachedqueries the useful work is a single reduce, but PHP interpreter startup +
process bookkeeping + table polling add fixed, often multi-second, latency.
What this does
flowview_parallel_backend(FlowView → Parallel Queries):Legacy PHP Runner(default) orFlowView Query Service, plusflowview_query_service_url/flowview_query_service_portfilefor endpointdiscovery.
parallel_database_query_run()replacesits
exec_background()launch with a singlePOST /run {query_ids}. Theservice reads the same
parallel_database_query/_shardrows, runs theidentical cache-aware map-reduce across a goroutine worker pool capped by
flowview_parallel_threads(routing map reads through MaxScale whenflowview_use_maxscaleis on), and writesresults+status = completeback — so the existing result retrieval (and multi-request UNION) is unchanged.
runs the legacy runner, so enabling it can never strand a query.
parallel_database_query_shard_cachetable, so a partition cached by eitherbackend is reused by the other (a cold partition is read once).
does inline (TTL expiry, aged-out partitions, deleted query/filter cache).
Service (
service/flowview-query)Pure Go +
go-sql-driver/mysql. Files:main.go,types.go,config.go,query.go,scheduler.go,server.go,demo.go, plusconfig.sample.json,a systemd unit, and a
README.mdwith the full analysis, compilation &install steps (incl. cross-compile), the DB users/GRANTs for the Cacti control
DB and FlowView data DB, MaxScale notes, and the endpoint reference.
Endpoints:
POST /run,GET /health,POST /maintenance,POST /cache/invalidate. It binds localhost on an available port and writesit to a port file for discovery.
Testing
go vet+gofmtclean;go buildsucceeds../flowview-query -selftestruns the full map-reduce/worker-pool/partition-cachepath in memory (no DB) and verifies the HTTP listener: cold run maps 4
partitions in parallel; warm run serves all 4 from cache (~100× faster);
GET /health → 200.php -lclean onsetup.phpandincludes/functions.php.Notes / scope
DB-backed path here (no MariaDB + flow data in this environment); the
in-memory self-test exercises the concurrency/cache/reduce mechanics.
flowview_parallel_threads,flowview_parallel_runlimit,flowview_parallel_time_to_live, andflowview_use_maxscaleby reading thelive Cacti
settings.