Skip to content

PolicySync Changelog Slow-Task Diagnostics

PolicySync includes opt-in, off-by-default diagnostics that help find the cause when a changelog occasionally takes far longer to process than its work warrants (for example, a single resource task that appears to hang). The diagnostics are part of the shared PolicySync changelog path, so they apply to every connector.

When enabled, the connector captures — on its own, without anyone attaching a debugger:

  • a slow-task WARN (to a dedicated file) naming the resource and the per-phase millisecond breakdown of any changelog resource task that runs longer than a threshold, and
  • an automatic in-process thread dump when a changelog's processing exceeds a threshold, so the stuck thread's stack is recorded while it is still stuck.

Both features are disabled by default (their thresholds are 0). On upgrade nothing changes and nothing is written; enabling them is an explicit operator decision, and the per-task overhead when disabled is a single comparison.

Note

The slow-task WARN and the thread dump only observe — a failure in either is caught and swallowed and can never change changelog processing or its outcome. The resource-process task time-box (policysync.changelog.resource.task.timeout.ms, off by default) is the exception: when you enable it, it deliberately changes processing — it abandons a task that overruns its processing budget (measured from when the task starts running) or its queue budget (policysync.changelog.resource.task.queue.timeout.ms, measured from submit) and releases the barrier so one stuck task cannot stall the whole changelog, and once retries are exhausted it marks the task failed with a RESOURCE_PROCESS_TASK_TIMEOUT audit.

Configuration

Set these in Privacera Manager. The primary thresholds — the slow-task WARN, the thread dump, and the resource-task time-box — all default to 0 (disabled) for every connector. You can enable them globally (set the variable so all connectors pick it up) or per connector instance — set the variable in that connector instance's custom vars (config/custom-vars/connectors/<connector>/<instance>/), which overrides the global default for that instance only. For example, enable the thread dump on the Databricks Unity Catalog instance while every other connector (Lake Formation, Snowflake, and so on) stays off.

Privacera Manager variable PolicySync property Default Meaning
CONNECTOR_CHANGELOG_SLOW_RESOURCE_TASK_WARN_MS policysync.changelog.slow.resource.task.warn.ms 0 (off) Emit a WARN with the per-phase breakdown for any changelog resource task that runs at least this many ms. 0 disables. Recommended when enabling: 30000.
CONNECTOR_CHANGELOG_SLOW_CHANGELOG_DUMP_MS policysync.changelog.slow.changelog.dump.ms 0 (off) Capture an automatic thread dump when a changelog's processing takes at least this many ms. 0 disables. Recommended when enabling: 600000 (10 min).
CONNECTOR_CHANGELOG_STALL_DUMP_COUNT policysync.changelog.stall.dump.count 3 Number of thread dumps captured per trigger.
CONNECTOR_CHANGELOG_STALL_DUMP_INTERVAL_MS policysync.changelog.stall.dump.interval.ms 30000 Interval (ms) between the dumps of a single trigger (30 s).
CONNECTOR_CHANGELOG_STALL_DUMP_RETENTION_HOURS policysync.changelog.stall.dump.retention.hours 24 Age bound (hours) for the dump/ directory; older files are evicted.
CONNECTOR_CHANGELOG_STALL_DUMP_MAX_TOTAL_MB policysync.changelog.stall.dump.max.total.mb 256 Cap on total dump/ size (MB); oldest-first eviction.
CONNECTOR_CHANGELOG_STALL_DUMP_MAX_FILES policysync.changelog.stall.dump.max.files 100 Cap on dump/ file count (so dumps do not grow without bound); oldest-first eviction.
CONNECTOR_CHANGELOG_STALL_DUMP_MIN_GAP_MS policysync.changelog.stall.dump.min.gap.ms 60000 Minimum gap (ms) between dump triggers, to rate-limit captures.
CONNECTOR_CHANGELOG_RESOURCE_TASK_TIMEOUT_MS policysync.changelog.resource.task.timeout.ms 0 (off) Processing budget (ms) for a changelog resource task, measured from when it starts running (queue wait excluded). A running task that overruns it is abandoned as stuck (best-effort cancel — not a hard kill), logged to the slow-task file, and the barrier is released so one stuck task does not block the whole changelog. 0 disables the whole time-box. Recommended when enabling: 300000 (5 min).
CONNECTOR_CHANGELOG_RESOURCE_TASK_QUEUE_TIMEOUT_MS policysync.changelog.resource.task.queue.timeout.ms 0 (no queue bound) Queue budget (ms), measured from submit. A task that never gets a pool thread within it is abandoned as abandonedWhileQueued — the safety valve that still releases the barrier when the pool is saturated by stuck threads. 0 leaves queued tasks unbounded (only safe when the pool reliably drains). Recommended when enabling: 3600000 (60 min), sized above the expected queue-drain ≈ (impacted resources ÷ pool threads) × per-task time.
CONNECTOR_CHANGELOG_RESOURCE_TASK_MAX_RETRIES policysync.changelog.resource.task.max.retries 0 Number of times a timed-out resource task is re-submitted before it is marked failed (with a RESOURCE_PROCESS_TASK_TIMEOUT audit). A retry does not free the stuck thread, so keep this count small (recommended 1); 0 = no retry.

The six stall.dump.* properties only take effect when the thread dump is enabled. The three resource.task.* properties are the independent resource-process task time-box, which is active only when policysync.changelog.resource.task.timeout.ms is non-zero. It uses two separate budgets — a processing budget measured from run-start (so a task merely waiting its turn in a deep queue is never abandoned as if it were stuck) and a queue budget measured from submit (the safety valve that releases the barrier when the pool is jammed). Size the queue budget above the expected queue depth when a small pool fans out many resource tasks.

When to enable

Enable these when a changelog is reported to be intermittently slow and you need to catch it in the act — the slowness is usually random, so attaching a debugger after the fact rarely works. Because everything is off by default, you turn on only what you need and turn it back off once you have collected the evidence.

Operator runbook

  1. Enable the diagnostics. In Privacera Manager, set the thresholds to the recommended values, then run the Privacera Manager update so the connector picks up the new policysync.properties:

    YAML
    CONNECTOR_CHANGELOG_SLOW_RESOURCE_TASK_WARN_MS: "30000"
    CONNECTOR_CHANGELOG_SLOW_CHANGELOG_DUMP_MS: "600000"
    

    Optionally, to also time-box an over-running resource task (abandon + log, release the barrier, and emit a RESOURCE_PROCESS_TASK_TIMEOUT audit after retries):

    YAML
    1
    2
    3
    CONNECTOR_CHANGELOG_RESOURCE_TASK_TIMEOUT_MS: "300000"
    CONNECTOR_CHANGELOG_RESOURCE_TASK_QUEUE_TIMEOUT_MS: "3600000"
    CONNECTOR_CHANGELOG_RESOURCE_TASK_MAX_RETRIES: "1"
    
  2. Reproduce, or wait for recurrence. Let the connector run until a slow changelog occurs again.

  3. Collect the output from the connector pod. The diagnostics write to the connector's log directory:

    • changelog-slow-task.log — one WARN line per slow resource task, with its resource key, resource type, principal count, and the per-phase millisecond breakdown. This file is written by a dedicated, file-only logger and is not sent to the console or logstash appenders.
    • dump/<YYYY-MM-DD>/<changeLogId>/ — the captured thread dumps (dump-00.txt, and so on) plus a summary file listing the in-flight resource keys and the step each was executing when the dump was taken.
    Bash
    1
    2
    3
    4
    kubectl exec -it <POD_NAME> -n <NAMESPACE> -- /bin/bash
    # inside the pod, under the connector log directory:
    ls -R dump/
    cat changelog-slow-task.log
    

    See Capturing a Thread Dump and Collecting Support Files for copying these files off the pod along with policysync.properties / connector.properties.

  4. Interpret the output. The WARN's per-phase breakdown tells you which phase of the task was slow; the summary file names the step each in-flight task was on; and the thread dumps show the exact stack of the stuck thread. Together these localize where the time went.

  5. Disable when done. Set the thresholds back to 0 and re-apply (include the time-box's CONNECTOR_CHANGELOG_RESOURCE_TASK_TIMEOUT_MS and CONNECTOR_CHANGELOG_RESOURCE_TASK_QUEUE_TIMEOUT_MS if you enabled them):

    YAML
    1
    2
    3
    4
    CONNECTOR_CHANGELOG_SLOW_RESOURCE_TASK_WARN_MS: "0"
    CONNECTOR_CHANGELOG_SLOW_CHANGELOG_DUMP_MS: "0"
    CONNECTOR_CHANGELOG_RESOURCE_TASK_TIMEOUT_MS: "0"
    CONNECTOR_CHANGELOG_RESOURCE_TASK_QUEUE_TIMEOUT_MS: "0"
    

Sensitive content

The WARN line and the dump summary contain resource identifiers (catalog / schema / table names), and are written to pod-local disk only. They are never shipped off the pod automatically. Treat the collected files as customer-identifying and mask as needed before sharing. Principal information is recorded as counts only, never names.