Reader setup
Before you choose
- One concrete failed or costly workflow with timestamps, scope and an owner.
- Access to configuration/measurement owners; use Create a read-only database account for safe VICIdial queries for optional SQL.
- Equivalent requirements and a current candidate offer for the migration comparison.
- Expected result
- A filled stay/improve/migrate decision with tested requirements, costs, unknowns and a next acceptance test.
- Before making changes
- No production change, index creation, port expansion or migration is prescribed by a symptom. Read-only probes can expose internal details; keep actual records private.
Start with the symptom and a measurement
Start with a falsifiable requirement: for example, “an authorized agent must receive this email, reply under the right identity and produce the required audit trail.” “We need omnichannel” is too broad to compare or test.
Keep three possible conclusions open: the existing deployment already supports the task; a bounded improvement can satisfy it; or a candidate platform satisfies an important requirement the current arrangement cannot meet at an acceptable cost.
You should seeThe requirement names an actor, an input, an observable outcome and the conditions under which it must hold.
- Write one mandatory workflow and the evidence needed to accept it.
- Separate a feature gap from an implementation, staffing or support gap.
- Keep improve, retain and migrate as testable options until the comparison is complete.
Separate the symptom, hypothesis and acceptance test
A busy-hour failure is an observation. Port exhaustion, a slow query, carrier throttling and agent availability are competing explanations. Write down the evidence needed to distinguish them before selecting a change.
- Before you use it
- This is an original fictional example, not a product endorsement or a measured deployment.
Requirement: after-hours inbound email gets a tracked response within the agreed window.Current observation: feature exists, but no support owner covers the window.Candidate A: keep VICIdial + add a named operating/support contract.Candidate B: managed platform + verify support scope and routing workflow.Acceptance: send an approved synthetic email after hours; verify routing, response identity, timestamps and exportable history.Decision today: pending quotes and two complete workflow tests.This sample is a template or reading aid, not a terminal command. There is no output to show.
- Success looks like
- The test distinguishes missing operations coverage from an absent software feature.
- Stop if
- Do not choose a platform while the mandatory workflow, contract coverage or cost is unknown.
- Record the symptom, time window, affected users and competing explanations.
- Name the observation that would support or reject each explanation.
- Leave unmeasured constraints unknown; a familiar symptom does not prove the cause.
Test media allocation and network behavior before naming a ceiling
A configured RTP range, a firewall rule and a current channel count are different observations. None alone measures allocated media sockets, packet loss or the busiest interval. Compare synchronized media/network telemetry with the actual affected call paths.
If the evidence identifies a constrained allocation or blocked path, plan a scoped change and its retest with the owner. If it does not, keep investigating. A large-looking unused range does not rule out NAT, addressing or packet-loss problems.
firewall-cmd --info-service=rtp prints a service definition. It does not show that the service is enabled in an active zone, or that the actual Asterisk range is permitted. Compare the loaded range with the relevant runtime zone and all applicable policy/provider rules; test the authorized media path separately. Do not reload or open a range as a diagnostic shortcut.
- Before you use it
- Use the approved root/read-only CLI context. Keep source ranges and firewall output private. Includes/defaults may supply the RTP range if this file has no active assignments.
grep -nE '^[[:space:]]*(rtpstart|rtpend)[[:space:]]*=' /etc/asterisk/rtp.confif command -v firewall-cmd >/dev/null 2>&1 && firewall-cmd --state; then firewall-cmd --get-active-zones printf '%s\n' 'Next: replace ACTUAL_ZONE with the interface/source zone above.' printf '%s\n' 'Read: firewall-cmd --zone=ACTUAL_ZONE --list-all'else printf '%s\n' 'STOP: identify the actual firewall backend and its owner; no allowance is established.'fiasterisk -rx 'core show channels count'This example has no recorded result here. Follow its preparation, expected result and stop conditions before using it.
- Success looks like
- You have the configured range, actual active zone/interface/source bindings and a call-count snapshot. Read the named zone with --list-all and have the network owner include applicable policies/direct/nftables rules and provider controls.
- Stop if
- A service definition, empty grep or one zone listing is not an allow verdict. Stop the capacity conclusion until the owner explains the effective rule path and the intended media test.
Measure competing account and media limits
- Record configured, permitted and observed allocation separately.
- Do not convert an Asterisk channel count directly into RTP-port use.
- Retest the affected call behavior after an approved change.
Correlate workload and contention across roles
Running database, web and dialer roles on one host is a topology fact, not a diagnosis. Measure the affected interval: CPU, storage latency, query duration, memory pressure, calls and scheduled jobs. Use a controlled comparison to establish contention.
The monthly row-count query below describes retained campaign log volume. It does not measure storage latency or prove that retention caused the incident. An archival or role-separation plan needs a recoverable copy and a task-specific acceptance test.
- Before you use it
- Run this read-only outside busy hours for one test campaign. It groups retained call rows by month; it does not measure total table growth.
SELECT DATE_FORMAT(call_date, '%Y-%m') AS call_month, COUNT(*) AS call_rowsFROM vicidial_logWHERE campaign_id = '<CAMPAIGN_ID>' AND call_date >= DATE_SUB(NOW(), INTERVAL 6 MONTH)GROUP BY call_monthORDER BY call_month;Captured demo response · 2026-09-24 22:25 UTC. Any filtering, hidden values or test-only data are identified in the capture label. Select Replay transcript to read the recorded output.
- Success looks like
- The query shows retained call rows grouped by month for the selected campaign; archived or deleted rows are absent, and the result does not measure total table size.
- Stop if
- An empty result may mean no retained rows match the campaign and period. Check the filters and retention policy before drawing a growth conclusion.
- Record role placement separately from measured contention.
- Compare retained row counts with retention and archival policy.
- Ask the responsible owner to test a proposed topology or retention change against the same workload and recovery requirement.
Inspect a slow query before changing indexes or report routing
Collect the actual slow query, its plan, table sizes and the conditions under which it is slow. Inspect existing indexes before proposing one. A missing index name is not proof that a new index helps this workload, and a populated replica setting is not proof that reports use a healthy replica.
The read-only inventory below records candidate inputs for the database owner. Measure the same report and source data before/after any separately reviewed change.
- Before you use it
- Run this read-only, through the approved sudo mysql --defaults-file=/etc/vicidial-readonly.cnf context after verifying SELECT CURRENT_USER(), DATABASE(), against your own install; a customized deployment can differ from the shipped schema if anyone has already added an index. The last statement reports whether slave_db_server is set rather than selecting its value, so a captured run never prints a real hostname.
SELECT TABLE_NAME, INDEX_NAME, COLUMN_NAME, SEQ_IN_INDEX FROM information_schema.STATISTICSWHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME IN ('vicidial_hopper', 'vicidial_live_agents', 'vicidial_log')ORDER BY TABLE_NAME, INDEX_NAME, SEQ_IN_INDEX; SELECT COALESCE(CHAR_LENGTH(slave_db_server), 0) > 0 AS slave_db_server_is_set, reports_use_slave_dbFROM system_settingsLIMIT 1;Captured demo response · 2026-09-24 22:25 UTC. Any filtering, hidden values or test-only data are identified in the capture label. Select Replay transcript to read the recorded output.
- Success looks like
- You can see, for your own tables, whether a composite index on campaign_id together with status or call_date already exists, and whether slave_db_server_is_set is 1 or 0 and reports_use_slave_db is populated.
- Stop if
- A missing index or unset report-slave value is a configuration observation, not proof of the cause of slowness. Inspect query plans, workload and replica health before deciding on a change.
You should seeThe proposed database action names a query and an acceptance measurement rather than relying on a configuration flag.
- Match proposed indexes to the actual query plan and write workload.
- Verify report routing and replica health; configuration presence alone does not establish either.
- Measure the affected report before and after any approved change.
Separate operational drop ratios from legal abandonment
A campaign’s logged DROP count can reveal an operational trend. Dividing it by all log rows does not produce the live-human abandonment measure described in the applicable rules. Call classification and timing need separate evidence.
Keep call mix, agent availability and measured results in the decision record. A dial-level change is not a substitute for a completed, compliant workflow.
- Before you use it
- Use the approved read-only session and replace <CAMPAIGN_ID>. Confirm the database timezone and that this log population matches the operational question.
SELECT DATE_FORMAT(call_date, '%Y-%m-%d') AS call_day, COUNT(*) AS logged_rows, SUM(CASE WHEN status = 'DROP' THEN 1 ELSE 0 END) AS drop_rows, ROUND(100 * SUM(CASE WHEN status = 'DROP' THEN 1 ELSE 0 END) / COUNT(*), 2) AS drop_share_of_log_rows_pctFROM vicidial_logWHERE campaign_id = '<CAMPAIGN_ID>' AND call_date >= DATE_SUB(NOW(), INTERVAL 14 DAY)GROUP BY call_dayORDER BY call_day;This example has no recorded result here. Follow its preparation, expected result and stop conditions before using it.
- Success looks like
- The ratio is explicitly DROP rows divided by selected log rows. It is not a count of people reached or a legal abandonment finding.
- Stop if
- Stop interpreting the rate if live-person classification, timing or the selected population is unknown; use Predictive vs power dialing: which mode fits your team for the distinct denominator discussion.
Dial-mode and live-answer measurement distinctions
- Name the status population and time window before calculating an operational ratio.
- Review live-person classification and timing separately for abandonment.
- Compare permitted trials under equivalent staffing and call-mix conditions; restore prior settings if agreed limits fail.
Use staffing counts only for the question they answer
The two queries count distinct users found in a historical log window and selected live-agent rows now. Neither calculates peak concurrent active sessions over the historical window. Treat stale rows, reconnects and campaign scope explicitly.
For license or capacity comparisons, use a reviewed session-overlap calculation or the platform’s documented peak metric. Keep named users, simultaneous sessions, channels and billed units in separate fields.
- Before you use it
- Run both statements read-only, through the approved sudo mysql --defaults-file=/etc/vicidial-readonly.cnf context after verifying SELECT CURRENT_USER(), DATABASE(); run the second query again during your actual busiest hour, not an average one, since a single snapshot can understate peak concurrency. This lab scopes both statements to one fixture campaign for a safe capture; on your own install, drop the campaign_id filter for an org-wide total.
SELECT COUNT(DISTINCT user) AS distinct_agents_last_30_daysFROM vicidial_logWHERE campaign_id = '<CAMPAIGN_ID>' AND call_date >= DATE_SUB(NOW(), INTERVAL 30 DAY); SELECT COUNT(*) AS agents_logged_in_right_nowFROM vicidial_live_agentsWHERE campaign_id = '<CAMPAIGN_ID>' AND status IN ('READY','INCALL','QUEUE','PAUSED');Captured demo response · 2026-09-24 22:25 UTC. Any filtering, hidden values or test-only data are identified in the capture label. Select Replay transcript to read the recorded output.
- Success looks like
- The first result is a distinct-user count over the chosen log window; the second is a point-in-time selected live-agent row count. Neither is historical peak concurrency.
- Stop if
- Repeat snapshots or use a time-series report to estimate the peak; compare each vendor’s definition of a licensed user before pricing.
- Match each quoted licensing unit to the same measured quantity.
- Use a reviewed historical overlap calculation or documented peak metric for peak concurrency.
- Keep distinct historical users and one live snapshot separate from peak concurrent active agents.
Test the exact channel, support and evidence requirement
VICIdial documents native customer/agent chat and inbound email handling. Do not list those channel names as missing features. Instead test the required routing, identity, history, permissions, accessibility, integration and support behavior on the installed version.
A managed offer can still be a better fit if it demonstrably meets mandatory operating coverage, recovery, reporting or contractual requirements that the current arrangement cannot provide economically. A logo, feature checkbox or generic “omnichannel” claim is not that demonstration.
- Run the mandatory workflow on the current installation and candidate under comparable conditions.
- Record actual channel behavior, integration needs and contracted support coverage.
- Obtain a current itemized quote with assumptions, exclusions and term before comparing costs.
Sources for this section
- Open-source VICIdial featuresVICIdial Group · Checked November 6, 2026
- Customer and agent chatVICIdial · Checked November 6, 2026
Complete a reversible decision record
Compare the same workload, support window, retention, integrations and recovery requirement over the same period. Include migration effort, overlap operation, number changes, training, internal support time and contractual exclusions. Unknown costs remain unknown.
Write a decision with a review date and a reversal or exit condition. A trial that fails the mandatory workflow should change the conclusion even if its headline price is lower.
- Fill the requirement and evidence rows in the downloadable record.
- Complete one bounded improvement test and one equivalent candidate workflow test where feasible.
- Compare the total responsibility/cost scope and unresolved mandatory criteria.
- Choose stay, improve, migrate or defer; name the next owner and test.
You should seeThe recommendation states which requirement was met, what remains unknown and what evidence would change it.
Download the platform decision record
Compare operating responsibilities and costs
- Document data, recording and configuration portability for every option, including the self-hosted deployment.
- Include implementation, training, parallel operation and ongoing ownership in the comparison.
- Set a review date, acceptance criteria and a reversible next action.
Checks and sources
What was checked
- Native customer/agent chat and inbound email capability are supported by the official feature and chat references reviewed November 6, 2026. Presence does not establish the reader’s required channel workflow, integrations or support coverage.
- The worked decision is fictional. No production capacity, incident-frequency or migration result is asserted; a configuration value is a hypothesis to test, not proof of the cause.
Primary references
Sources
- Open-source VICIdial featuresVICIdial Group · accessed November 6, 2026
- Customer and agent chatVICIdial · accessed November 6, 2026
- VICIdial PJSIP SupportVICIdial · accessed November 6, 2026
- SIP Trunking scale and limitsTwilio · accessed November 6, 2026
- firewall-cmd service and active-zone queriesfirewalld · accessed November 7, 2026