Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
bace293
Show filter status and repair missing enabled state
alcatron Oct 18, 2026
56ac135
Remove unused sorting direction from status header
alcatron Oct 18, 2026
ce14e35
Repair filter schema in background and preserve schedule associations
alcatron Oct 18, 2026
e02dfb4
Share pending filter upgrade handling across web entry points
alcatron Oct 18, 2026
333d835
Format disabled filter labels consistently with Cacti gettext
alcatron Oct 18, 2026
df7549a
Preserve scheduled reports while filter migration is pending
alcatron Oct 18, 2026
3d38365
Preserve the core process helper return contract in tests
alcatron Oct 18, 2026
d829bd3
Retain original queue occurrences through FlowView-owned dispatch
alcatron Oct 18, 2026
5fff8c9
Keep failed schedules from starving healthy queue entries
alcatron Oct 18, 2026
3ced852
Recover dead scheduler registrations without removing live children
alcatron Oct 18, 2026
f46b031
Retain refused reports and concurrent child reservations
alcatron Oct 18, 2026
ca7e07f
test: verify queue fairness and background filter repair
alcatron Oct 19, 2026
bed4004
fix: retain scheduled reports after late schema readiness failure
alcatron Oct 19, 2026
8f9e856
fix: isolate filter schema repair in background upgrade helper
alcatron Oct 19, 2026
fbee2fd
fix: distinguish empty scheduled reports from query failures
alcatron Oct 19, 2026
5eefb7d
fix: distinguish failed lookups and uncached empty query results
alcatron Oct 19, 2026
7e45190
fix: propagate partition metadata failures to scheduled retries
alcatron Oct 19, 2026
c66e32c
fix: claim scheduled work atomically and reject invalid parallel results
alcatron Oct 19, 2026
94d2bc6
Preserve scheduled retries on parallel query failures
alcatron Oct 19, 2026
89f4c5a
Recreate failed parallel requests and reject partial results
alcatron Oct 19, 2026
bd9702a
Retry completed report cleanup without resending delivery
alcatron Oct 19, 2026
ceff2b4
Reject partial parallel reports when materialization fails
alcatron Oct 19, 2026
716acbe
Use child exit status to avoid resending reports with warnings
alcatron Oct 19, 2026
509c93b
Release owned upgrade registrations on every exit path
alcatron Oct 19, 2026
72c6104
Reconcile report child outcomes before retrying timed out work
alcatron Oct 19, 2026
537dca1
Require recorded child outcomes and isolate completion cleanup budget
alcatron Oct 19, 2026
ffbf5a4
Merge develop and resolve filter status changelog conflict
alcatron Oct 20, 2026
09755b6
Retry notification lookup failures before report delivery
alcatron Oct 20, 2026
a3bc078
Preserve uncertain notification outcomes across Cacti versions
alcatron Oct 20, 2026
59d8b6b
Accept CC-only and BCC-only report recipients
alcatron Oct 20, 2026
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

--- develop ---

* fix: Persist filter enabled state on fresh and existing installations, show enabled/disabled filter and schedule status using theme colours, and exclude disabled filters from report and schedule selection
* fix: Make bundled Net_DNS2 constructor nullability explicit for PHP 8.4 without changing accepted arguments

* issue: Shorten the graph drilldown button title from 'View NetFlow Traffic In Range' to 'NetFlow' so it reads cleanly as a label in Cacti's graph action menu
Expand Down
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,3 +211,37 @@ resolution.

-----------------------------------------------
Copyright (c) 2004-2026 - The Cacti Group, Inc.

### Filter and schedule status

Filters and schedules show Enabled in green and Disabled in grey, using the Cacti theme status classes. A disabled filter is excluded from report and schedule selectors and does not run scheduled reports. Disabling a filter does not stop its listener or delete history. Installations missing the filter state column retain existing filters as enabled when the column is created.

Missing filter-state columns are repaired by the background upgrade process, including same-version repairs. Pages return a retry message until repair completes; scheduled reports defer without issuing schema changes. Editing a schedule retains its existing disabled filter and labels it Disabled.

Pending filter-state migration leaves scheduled queue entries and lastsent/start timestamps unchanged. FlowView uses its own dispatcher on both Cacti versions: deferred or failed children retain their original occurrence, without saving a replacement. Native queue IDs and the older report-ID convention are both accepted. If resetting the retained row to pending fails, the row is kept and a queue-repair error is logged.

Queue dispatch processes a bounded snapshot, attempting each occurrence once per pass. A failed occurrence stays retained while healthy entries continue; previously attempted rows sort behind new work so repeated failures cannot monopolize the next snapshot. Schema loss or exhausted concurrency stops the pass.

Scheduler capacity checks remove exact child registrations only when the operating system confirms that their PID no longer exists. Live or uncertain processes (including permission errors and platforms without POSIX liveness probes) retain their capacity reservation. Failed legacy queue resets now log an explicit queue-repair error while retaining the original occurrence.


FlowView uses one dispatcher on both supported Cacti versions. A child records
`complete` after successful preparation/delivery and saved schedule timestamps,
or `retry` only for a known pre-delivery deferral. These markers let a later
poller reconcile a child that finishes after its parent's timeout. Completed
occurrences are deleted without executing them again. Only pending work or an
explicit retry marker can start a new child.

Every started child requires a recorded outcome, including an exit code of zero.
A timeout, crash or early exit with no recorded outcome leaves the occurrence `running` and
logs its queue ID instead of automatically resending it. If it remains unresolved,
check the child process and report/notification logs, then reconcile the specific
`reports_queued` row: remove an already-delivered occurrence only after repairing
its schedule timestamps, or return a confirmed undelivered occurrence to pending.
Do not reset an unresolved row merely because its process has disappeared.

Completion cleanup and executable reports use separate bounded snapshots, so
persistent cleanup failures cannot consume the pending-work budget. Cleanup
still runs first and does not require a free execution slot.

Scheduled FlowView notifications use one observable delivery helper on Cacti 1.2 and 1.3. A failed queue lookup before delivery requests retry. A returned mailer error, invalid notification configuration, or failed report-log write holds the occurrence for manual reconciliation without advancing schedule timestamps. This includes partial delivery to multiple notification targets; it is never automatically resent.
3 changes: 2 additions & 1 deletion flowview.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
require_once($config['base_path'] . '/lib/time.php');

flowview_connect();
flowview_require_filter_status();

set_default_action();

Expand Down Expand Up @@ -321,7 +322,7 @@ function load_session_for_filter() {
WHERE id = ?',
array(get_request_var('query')));

if (cacti_sizeof($query)) {
if (cacti_sizeof($query) && ($query['enabled'] ?? '') === 'on') {
foreach($query as $column => $value) {
switch($column) {
case 'name':
Expand Down
7 changes: 7 additions & 0 deletions flowview_filters.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
require_once($config['base_path'] . '/lib/timespan_settings.php');

flowview_connect();
flowview_require_filter_status();

set_default_action();

Expand Down Expand Up @@ -382,6 +383,10 @@ function clearFilter() {
'align' => 'right',
'sort' => 'ASC'
),
'nosort2' => array(
'display' => __('Status', 'flowview'),
'align' => 'center'
),
'nosort1' => array(
'display' => __('Resolution', 'flowview'),
'align' => 'right',
Expand Down Expand Up @@ -421,6 +426,8 @@ function clearFilter() {
form_selectable_cell($type, $filter['id']);
form_selectable_cell($filter['id'], $filter['id'], '', 'right');
form_selectable_cell($sort, $filter['id'], '', 'right');
$status = flowview_filter_status($filter);
form_selectable_cell('<span class="' . $status['class'] . '">' . $status['label'] . '</span>', $filter['id'], '', 'center');
form_selectable_cell($filter['resolve'], $filter['id'], '', 'right');
form_checkbox_cell($filter['name'], $filter['id']);

Expand Down
11 changes: 4 additions & 7 deletions flowview_schedules.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
require_once($config['base_path'] . '/plugins/flowview/includes/functions.php');

flowview_connect();
flowview_require_filter_status();

set_default_action();

Expand All @@ -56,12 +57,7 @@

$formats = reports_get_format_files();

$query_array = array_rekey(
flowview_db_fetch_assoc('SELECT id, name
FROM plugin_flowview_queries
ORDER BY name'),
'id', 'name'
);
$query_array = flowview_schedule_filters((int) get_filter_request_var('id'));

if (db_table_exists('plugin_notification_lists')) {
$notification_lists = array_rekey(
Expand Down Expand Up @@ -1038,7 +1034,8 @@ function clearFilter() {
form_selectable_cell('-', $row['id'], '', 'right');
}

form_selectable_cell(($row['enabled'] == 'on' ? "<span class='deviceUp'><b>" . __('Yes', 'flowview') . "</b></span>":"<span class='deviceDown'><b>" . __('No', 'flowview') . "</b></span>"), $row['id'], '', 'right');
$status = flowview_filter_status($row);
form_selectable_cell('<span class="' . $status['class'] . '">' . $status['label'] . '</span>', $row['id'], '', 'right');
form_checkbox_cell($row['name'], $row['id']);

form_end_row();
Expand Down
32 changes: 22 additions & 10 deletions flowview_upgrade.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@
+-------------------------------------------------------------------------+
*/

chdir('../../');
chdir(__DIR__ . '/../../');
require('./include/cli_check.php');
require_once('./plugins/flowview/includes/functions.php');
require_once('./plugins/flowview/setup.php');
require_once('./plugins/flowview/includes/database.php');
require_once('./plugins/flowview/includes/filter_upgrade.php');

flowview_connect();

Expand Down Expand Up @@ -81,25 +82,36 @@
$info = plugin_flowview_version();
$current_version = $info['version'];

/* do a version check */
if ($forcever == '' && $old_version == $current_version) {
cacti_log('Your Flowview is already up to date (v' . $current_version . ' vs v' . $old_version . ') not upgrading. Use --forcever to override', true, 'FLOWVIEW');
exit(0);
}

if (!register_process_start('flowview', 'upgrade', 1, 86400)) {
$registered = register_process_start('flowview', 'upgrade', 1, 86400);
if (!$registered) {
if (empty($forcever)) {
print 'WARNING: Running process detected. To override use --forcever' . PHP_EOL;
exit(1);
}
}

if ($registered) {
$upgrade_pid = getmypid();
register_shutdown_function(static function () use ($upgrade_pid) {
unregister_process('flowview', 'upgrade', 1, $upgrade_pid);
});
}

if (!flowview_filter_status_upgrade()) {
cacti_log('FlowView filter state upgrade failed; it will be retried.', true, 'FLOWVIEW');
exit(1);
}

/* do a version check */
if ($forcever == '' && $old_version == $current_version) {
cacti_log('Your Flowview is already up to date (v' . $current_version . ' vs v' . $old_version . ') not upgrading. Use --forcever to override', true, 'FLOWVIEW');
exit(0);
}

cacti_log('Upgrading from v' . $old_version . ' to ' . $current_version, true, 'FLOWVIEW');

flowview_upgrade($current_version, $old_version);

unregister_process('flowview', 'upgrade', 1);

exit(0);

/**
Expand Down
5 changes: 5 additions & 0 deletions includes/database.php
Original file line number Diff line number Diff line change
Expand Up @@ -514,3 +514,8 @@ function flowview_db_get_table_column_types($table, mixed $cnn_id = false) {

return $cols;
}

/** Check live metadata without Cacti's per-request column cache. */
function flowview_filter_status_ready(): bool {
return (bool) flowview_db_fetch_row("SHOW COLUMNS FROM plugin_flowview_queries LIKE 'enabled'", false);
}
18 changes: 18 additions & 0 deletions includes/filter_upgrade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
/* Copyright (C) 2004-2026 The Cacti Group. GPL-2.0-or-later. */

// Loaded by flowview_upgrade.php after Cacti's CLI bootstrap. Keep schema
// mutations out of database.php, which is included by ordinary web requests.
/** Repair legacy state only from the background upgrade process. */
function flowview_filter_status_upgrade(): bool {
if (!flowview_db_table_exists('plugin_flowview_queries')) {
return false;
}
if (flowview_filter_status_ready()) {
return true;
}
if (flowview_db_execute("ALTER TABLE plugin_flowview_queries ADD COLUMN enabled char(2) NOT NULL DEFAULT 'on' AFTER name", false)) {
return true;
}
return flowview_filter_status_ready();
}
Loading