Queue Management & mod_callcenter
This guide provides a comprehensive deep dive into queue management in the Ominis Cluster Manager, including mod_callcenter fundamentals, the one-pod-per-queue architecture, and complete lifecycle management.
What is a Queue?
At its core, a queue is a virtual waiting room for callers waiting to be connected to an available agent. Think of it like a digital version of waiting in line at a bank or store.
Key Concepts
- Queue: A container that holds callers and manages the connection to agents
- Callers: Also called "members" - people waiting in the queue
- Agents: People who answer the calls
- Strategy: Rules that determine how calls are distributed to agents
- Tiers: Connections between agents and queues that define priority
Example Scenario: A customer calls your support line → They enter the "support" queue → Music plays while they wait → An available agent is selected based on the queue strategy → The call connects to that agent.
mod_callcenter Concepts Deep Dive
FreeSWITCH's mod_callcenter is the engine that powers queue management. Understanding its core concepts is essential for effective queue configuration.
1. Queues
A queue is the organizational container for call flow.
Properties:
- Name: Unique identifier (e.g., "sales", "support", "billing")
- Strategy: Algorithm for distributing calls (see Queue Strategies)
- Configuration: Timeouts, music on hold, announcements, tier rules
- Pod Mapping: In Ominis, each queue maps to exactly one FreeSWITCH pod
Database Schema:
CREATE TABLE cc_queues (
name VARCHAR(255) PRIMARY KEY,
strategy VARCHAR(50),
moh_sound VARCHAR(255),
announce_frequency INT,
max_wait_time INT,
tier_rules_apply BOOLEAN,
-- ... additional configuration
);
2. Agents (Call Center Agents)
Agents are the people who answer calls from queues.
Properties:
- Name: Unique identifier for the agent
- Type:
callback(calls agent) oruuid-standby(agent calls in) - Contact: SIP URI where agent can be reached (e.g.,
user/agent_001@domain.com) - Status: Current availability state
- State: Current operational state
- Timings: Configuration for wrap-up time, delays, etc.
Agent Status
The status determines whether an agent can receive calls:
| Status | Description | Can Receive Calls? |
|---|---|---|
Logged Out | Agent is not working | ❌ No |
Available | Ready to take calls | ✅ Yes |
Available (On Demand) | Ready but requires explicit routing | ⚠️ Manual only |
On Break | Temporarily unavailable | ❌ No |
Agent State
The state reflects what the agent is currently doing:
| State | Description |
|---|---|
Waiting | Idle, ready for next call |
Receiving | Incoming call is ringing |
In a queue call | Currently on a call |
Idle | Available but not actively waiting |
Reserved | Reserved for a specific call |
Agent Contact Format
The contact field tells FreeSWITCH how to reach the agent:
# Direct SIP extension
user/1001@domain.com
# Sofia gateway
sofia/gateway/registrar/agent-10720
# SIP URI
sip:agent@192.168.1.100:5060
Example Agent:
{
"name": "john@example.com",
"type": "callback",
"contact": "sofia/gateway/registrar/agent-10720",
"status": "Available",
"state": "Waiting",
"max_no_answer": 3,
"wrap_up_time": 10,
"busy_delay_time": 60
}
3. Tiers (Agent-Queue Associations)
Tiers connect agents to queues and define priority routing.
Why Tiers?
- Allows agents to work multiple queues
- Defines priority levels for overflow and escalation
- Controls the order agents are tried within the same priority
Properties:
- Queue: Queue name
- Agent: Agent name
- Level: Priority tier (1 = highest, 9 = lowest)
- Position: Order within the same level (1 = first, 2 = second, etc.)
- State: Current tier state (
Ready,Standby,Active Inbound, etc.)
Priority System Example
Queue: "sales"
┌─────────────────────────────────────┐
│ Level 1 (Highest Priority) │
│ Position 1: john@example.com │ ← Tried first
│ Position 2: jane@example.com │ ← Tried second
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Level 2 (Overflow) │
│ Position 1: backup@example.com │ ← Only if Level 1 unavailable
└─────────────────────────────────────┘
How It Works:
- Call enters "sales" queue
- System tries Level 1 agents first (john, then jane)
- If no Level 1 agent answers within configured timeout
- System escalates to Level 2 agents (backup)
- Process repeats until call is answered or times out
Tier Rules (optional):
tier_rules_apply: Enable tier-based waitingtier_rule_wait_second: Seconds to wait before trying next leveltier_rule_wait_multiply_level: Multiply wait time by level (e.g., Level 2 waits 2x)tier_rule_no_agent_no_wait: Don't wait if no agents available
4. Members (Callers in Queue)
Members represent inbound callers waiting in a queue.
Properties:
- UUID: Unique identifier for the call
- Queue: Queue name
- Session UUID: FreeSWITCH call session ID
- CID Number/Name: Caller ID information
- Joined Epoch: Timestamp when caller entered queue
- State: Current member state
- Serving Agent: Agent currently handling the call (if answered)
Member States
| State | Description |
|---|---|
Waiting | In queue, waiting for agent |
Trying | System is attempting to connect to agent |
Answered | Connected to an agent |
Abandoned | Caller hung up before being answered |
Example Member:
{
"uuid": "12345678-1234-1234-1234-123456789012",
"queue": "support",
"session_uuid": "87654321-4321-4321-4321-210987654321",
"cid_number": "+1234567890",
"cid_name": "John Customer",
"joined_epoch": 1640995200,
"state": "Waiting",
"serving_agent": null
}
5. The Complete Picture
Here's how all the pieces work together:
One-Pod-Per-Queue Architecture
Ominis takes a unique approach: every queue runs in its own isolated Kubernetes pod.
Why One Pod Per Queue?
Traditional PBX systems run all queues in a single shared FreeSWITCH instance. Ominis deliberately does the opposite.
Benefits
-
Complete Isolation
- One queue's problems don't affect others
- Security boundary per customer/queue
- Independent configuration per queue
-
Independent Scaling
- Scale high-volume queues without affecting low-volume ones
- Right-size resources per queue
- Add capacity exactly where needed
-
Fault Tolerance
- One queue failure doesn't bring down others
- Restart individual queues without system-wide impact
- Easier debugging and troubleshooting
-
Resource Allocation
- Clear CPU/memory limits per queue
- Predictable performance characteristics
- Fair resource sharing via Kubernetes
-
Multi-Tenancy
- Separate customer data at infrastructure level
- Compliance-friendly isolation
- Per-tenant billing and monitoring
Trade-offs
- More Kubernetes Resources: More pods means more cluster overhead
- Higher Operational Complexity: More deployments to manage
- Resource Overhead: Each pod has base FreeSWITCH overhead (~50-100MB)
Decision: The benefits of isolation, security, and scalability outweigh the resource costs for a production call center platform.
Pod Components
Each queue pod contains:
Queue Pod (e.g., freeswitch-queue-sales)
├── FreeSWITCH Process
│ ├── mod_callcenter # Queue engine
│ ├── mod_sofia # SIP stack
│ ├── mod_xml_curl # Dynamic configuration
│ ├── mod_odbc # Database integration
│ └── mod_xml_rpc # API control
│
├── Configuration (Kubernetes)
│ ├── Deployment # Pod definition
│ ├── ConfigMap # FreeSWITCH config
│ └── Service # Network exposure
│
├── Networking
│ ├── SIP Port # 5060 + offset (e.g., 5160)
│ ├── RTP Ports # 16384-32768 (subset)
│ ├── XML-RPC Port # 8080 (internal only)
│ └── Health Check Port # 8888
│
└── Storage (optional)
└── Recordings # Call recordings (if enabled)
Architecture Diagram
Queue Lifecycle
Creation Flow
Startup Process
- API Receives Request:
POST /v1/queues - Extension Creation: Creates SIP extension
queue-{name}for authentication - Password Generation: Auto-generates secure SIP password
- Database Storage: Saves queue configuration to PostgreSQL
- Template Rendering: Generates Kubernetes YAML from template
- K8s Apply: Creates Deployment, Service, ConfigMap
- Pod Start: Kubernetes schedules and starts pod
- FreeSWITCH Init: Loads configuration from database via ODBC
- mod_callcenter Load: Initializes queue with agents/tiers
- SIP Registration: Registers with FreeSWITCH registrar
- Health Check: Health server responds on port 8888
- Ready: Pod becomes ready, starts accepting calls
Update Process
When updating a queue (e.g., changing strategy):
- API Receives Update:
PUT /v1/queues/sales - Database Update: Updates queue configuration
- Template Re-render: Generates updated YAML
- Server-Side Apply: K8s patches existing resources (no downtime)
- Configuration Reload: FreeSWITCH reloads from database
- mod_callcenter Pickup: Polls database (~100ms), applies changes
Note: Most configuration changes are picked up without restart. For major changes (SIP ports, etc.), a restart may be required.
Restart Process
To restart a queue without deleting it:
POST /v1/queues/sales/restart
What Happens:
- API deletes the pod (NOT the Deployment)
- Kubernetes immediately recreates pod (same configuration)
- New pod starts, loads same config from database
- SIP re-registers, queue becomes ready again
- Downtime: ~5-15 seconds
Use Cases:
- Apply configuration that requires restart
- Recover from stuck state
- Clear cache/temporary state
Deletion Process
What Gets Deleted:
- ✅ Kubernetes Deployment
- ✅ Kubernetes Service
- ✅ Kubernetes ConfigMap
- ✅ SIP extension from database
- ⚠️ Queue config (archived, not hard-deleted)
- ⚠️ Agent/tier assignments (preserved)
- ⚠️ Historical call data (preserved)
Queue Strategies
The strategy determines how calls are distributed to agents.
1. ring-all
Ring all available agents simultaneously. First to answer gets the call.
Use Case: When you want fastest possible answer time and all agents are equally qualified.
Behavior:
- Rings all Available agents in all tiers at once
- First agent to answer wins
- Other rings are cancelled
Example:
{
"name": "emergency",
"strategy": "ring-all",
"description": "Emergency hotline - fastest answer wins"
}
2. longest-idle-agent
Route to the agent who has been idle the longest. Default and most common strategy.
Use Case: Fair distribution of calls among agents.
Behavior:
- Tracks last call time for each agent
- Always tries agent with longest idle time first
- Fair workload distribution over time
Example:
{
"name": "support",
"strategy": "longest-idle-agent",
"tier_rules_apply": true
}
3. round-robin
Distribute calls evenly in circular order.
Use Case: Ensures equal call volume per agent.
Behavior:
- Maintains pointer to "next agent"
- Advances pointer after each call attempt
- Cycles through all agents repeatedly
Example:
{
"name": "sales",
"strategy": "round-robin"
}
4. top-down
Always try agents in order from position 1 to N.
Use Case: Prioritize senior agents, use juniors as overflow.
Behavior:
- Always starts with position 1
- Only moves to next position if previous unavailable
- Predictable, hierarchical routing
Example:
{
"name": "vip_support",
"strategy": "top-down",
"tier_rules_apply": true
}
Agent Order:
- Level 1, Position 1: Senior agent (gets most calls)
- Level 1, Position 2: Mid-level agent (gets overflow)
- Level 2, Position 1: Junior agent (gets overflow from Level 1)
5. agent-with-least-talk-time
Route to agent with lowest total talk time.
Use Case: Balance workload by actual time spent on calls.
Behavior:
- Tracks cumulative talk time per agent
- Routes to agent with least total talk time
- Self-balancing over time
Example:
{
"name": "billing",
"strategy": "agent-with-least-talk-time"
}
6. agent-with-fewest-calls
Route to agent with fewest total calls answered.
Use Case: Balance by call count rather than time.
Behavior:
- Tracks call count per agent
- Routes to agent with lowest count
- Useful when calls have similar durations
Example:
{
"name": "intake",
"strategy": "agent-with-fewest-calls"
}
7. sequentially-by-agent-order
Try agents in strict sequential order (like top-down, but more rigid).
Use Case: Strict priority routing with no randomness.
Behavior:
- Strict sequential order by tier level and position
- No load balancing considerations
- Predictable, deterministic routing
8. random
Randomly select an available agent.
Use Case: Testing, simple distribution when fairness doesn't matter.
Behavior:
- Random selection from available agents
- No fairness or load balancing
- Simple but uneven distribution
Port Allocation
Each queue pod requires dedicated ports to avoid conflicts.
Port Types
| Port Type | Purpose | Range | Example |
|---|---|---|---|
| SIP | SIP signaling | 5060 + offset | Queue 1: 5160, Queue 2: 5260 |
| RTP | Media (audio) streams | 16384-32768 (subset) | Queue 1: 16384-20000 |
| XML-RPC | API control | 8080 | All queues use 8080 internally |
| Health | Health check | 8888 | All queues use 8888 internally |
Port Offset Strategy
To avoid conflicts, queues use port offsets:
Base SIP Port: 5060
Queue "sales": SIP 5160 (5060 + 100*1)
Queue "support": SIP 5260 (5060 + 100*2)
Queue "billing": SIP 5360 (5060 + 100*3)
RTP Port Allocation
RTP ports are allocated in non-overlapping ranges:
Queue "sales": 16384-20000 (3,616 ports)
Queue "support": 20001-24000 (4,000 ports)
Queue "billing": 24001-28000 (4,000 ports)
Calculation:
- Each concurrent call needs 2 ports (one for each side)
- 4,000 ports = ~2,000 concurrent calls per queue
- Adjust
rtp_start_portandrtp_end_portas needed
Service Exposure
apiVersion: v1
kind: Service
metadata:
name: freeswitch-queue-sales
spec:
selector:
queue: sales
ports:
- name: sip
port: 5160
protocol: UDP
- name: xmlrpc
port: 8080
protocol: TCP
- name: health
port: 8888
protocol: TCP
ADR: One Pod Per Queue vs Shared Instance
Context
Traditional call center systems typically run all queues in a single shared FreeSWITCH instance. This is more resource-efficient but creates tight coupling between queues.
Decision
Deploy a separate Kubernetes pod for each queue.
Alternatives Considered
Alternative 1: Shared FreeSWITCH Instance
Approach: Run all queues in one FreeSWITCH instance.
Pros:
- ✅ More resource-efficient (one process, shared memory)
- ✅ Simpler operational model (fewer moving parts)
- ✅ Lower Kubernetes overhead
- ✅ Traditional approach, well-understood
Cons:
- ❌ Single point of failure (one crash affects all queues)
- ❌ Resource contention (high-volume queue starves others)
- ❌ Security risks (all customers share same process)
- ❌ Difficult to isolate and debug issues
- ❌ Scaling affects all queues equally (can't scale just one)
- ❌ Configuration complexity (all queues in same config)
Alternative 2: One Pod Per Queue (Chosen)
Approach: Deploy isolated pod for each queue.
Pros:
- ✅ Complete isolation (one failure doesn't cascade)
- ✅ Independent scaling (scale hot queues independently)
- ✅ Clear security boundaries (customer data separation)
- ✅ Easier debugging (isolated logs, metrics per queue)
- ✅ Predictable performance (dedicated resources)
- ✅ Compliance-friendly (tenant isolation)
Cons:
- ⚠️ More Kubernetes resources (more pods to manage)
- ⚠️ Higher memory overhead (~50-100MB base per pod)
- ⚠️ More complex orchestration
- ⚠️ Slightly slower to provision (K8s scheduling per pod)
Consequences
Positive
- Security: Customer A's queue cannot access Customer B's data
- Reliability: One queue failure doesn't affect others
- Scalability: Scale queues independently based on load
- Observability: Clear per-queue metrics and logs
- Performance: No resource contention between queues
Negative
- Cost: Higher baseline resource usage
- Complexity: More K8s objects to manage (deployments, services, configmaps)
- Provisioning Time: Creating queue takes ~5-15 seconds (K8s scheduling)
Mitigation
- Use Kubernetes resource limits to right-size pods
- Implement pod affinity/anti-affinity for optimal scheduling
- Cache queue templates for faster provisioning
- Use metrics to identify and consolidate underutilized queues
Status
Accepted - This is the production architecture.
API Endpoints
Queue Management
Create Queue
Creates a new queue with dedicated pod.
POST /v1/queues
Request Body:
{
"name": "sales",
"strategy": "longest-idle-agent",
"description": "Sales team queue",
"max_wait_time": 300,
"tier_rules_apply": true,
"tier_rule_wait_second": 10,
"tier_rule_no_agent_no_wait": false,
"global_codec_prefs": "OPUS,G722,PCMU,PCMA",
"outbound_codec_prefs": "OPUS,G722,PCMU,PCMA",
"max_sessions": 1000,
"sessions_per_second": 100
}
Response (201 Created):
{
"queue": {
"name": "sales",
"strategy": "longest-idle-agent",
"moh_sound": "$${hold_music}",
"max_wait_time": 300,
"tier_rules_apply": true
}
}
cURL Example:
curl -X POST http://localhost:8000/v1/queues \
-H "X-API-Key: demo" \
-H "Content-Type: application/json" \
-d '{
"name": "sales",
"strategy": "longest-idle-agent",
"max_wait_time": 300,
"tier_rules_apply": true
}'
List Queues
Retrieve all queues.
GET /v1/queues
Response (200 OK):
{
"queues": [
{
"name": "sales",
"strategy": "longest-idle-agent",
"max_wait_time": 300
},
{
"name": "support",
"strategy": "ring-all",
"max_wait_time": 600
}
],
"total": 2
}
cURL Example:
curl -X GET http://localhost:8000/v1/queues \
-H "X-API-Key: demo"
Get Queue Details
Retrieve details for a specific queue.
GET /v1/queues/{queue_name}
Response (200 OK):
{
"queue": {
"name": "sales",
"strategy": "longest-idle-agent",
"moh_sound": "$${hold_music}",
"announce_frequency": 30,
"max_wait_time": 300,
"tier_rules_apply": true,
"tier_rule_wait_second": 10,
"max_sessions": 1000,
"global_codec_prefs": "OPUS,G722,PCMU,PCMA"
}
}
cURL Example:
curl -X GET http://localhost:8000/v1/queues/sales \
-H "X-API-Key: demo"
Update Queue
Update queue configuration.
PUT /v1/queues/{queue_name}
Request Body:
{
"strategy": "ring-all",
"max_wait_time": 600,
"announce_frequency": 45
}
Response (200 OK):
{
"queue": {
"name": "sales",
"strategy": "ring-all",
"max_wait_time": 600,
"announce_frequency": 45
}
}
cURL Example:
curl -X PUT http://localhost:8000/v1/queues/sales \
-H "X-API-Key: demo" \
-H "Content-Type: application/json" \
-d '{
"strategy": "ring-all",
"max_wait_time": 600
}'
Restart Queue
Restart queue pod (deletes and recreates).
POST /v1/queues/{queue_name}/restart
Response (204 No Content)
cURL Example:
curl -X POST http://localhost:8000/v1/queues/sales/restart \
-H "X-API-Key: demo"
Delete Queue
Delete a queue and its pod.
DELETE /v1/queues/{queue_name}
Response (204 No Content)
cURL Example:
curl -X DELETE http://localhost:8000/v1/queues/sales \
-H "X-API-Key: demo"
Get Queue Count
Get real-time statistics for a queue.
GET /v1/queues/{queue_name}/count
Response (200 OK):
{
"queue": "sales",
"count": 5,
"waiting": 3,
"trying": 1,
"answered": 1,
"abandoned": 0
}
cURL Example:
curl -X GET http://localhost:8000/v1/queues/sales/count \
-H "X-API-Key: demo"
Complete Example: Setting Up a Queue
Let's walk through setting up a complete queue with agents and tiers.
Step 1: Create Queue
curl -X POST http://localhost:8000/v1/queues \
-H "X-API-Key: demo" \
-H "Content-Type: application/json" \
-d '{
"name": "support",
"strategy": "longest-idle-agent",
"max_wait_time": 300,
"tier_rules_apply": true,
"tier_rule_wait_second": 10
}'
Step 2: Create Agents
# Senior Agent (John)
curl -X POST http://localhost:8000/v1/agents \
-H "X-API-Key: demo" \
-H "Content-Type: application/json" \
-d '{
"name": "john@example.com",
"type": "callback",
"contact": "sofia/gateway/registrar/agent-10720",
"max_no_answer": 3,
"wrap_up_time": 10
}'
# Mid-level Agent (Jane)
curl -X POST http://localhost:8000/v1/agents \
-H "X-API-Key: demo" \
-H "Content-Type: application/json" \
-d '{
"name": "jane@example.com",
"type": "callback",
"contact": "sofia/gateway/registrar/agent-10721",
"max_no_answer": 3,
"wrap_up_time": 10
}'
# Junior Agent (Bob)
curl -X POST http://localhost:8000/v1/agents \
-H "X-API-Key: demo" \
-H "Content-Type: application/json" \
-d '{
"name": "bob@example.com",
"type": "callback",
"contact": "sofia/gateway/registrar/agent-10722",
"max_no_answer": 3,
"wrap_up_time": 10
}'
Step 3: Assign Agents to Queue (Tiers)
# John: Level 1, Position 1 (first priority)
curl -X POST http://localhost:8000/v1/tiers \
-H "X-API-Key: demo" \
-H "Content-Type: application/json" \
-d '{
"queue": "support",
"agent": "john@example.com",
"level": 1,
"position": 1,
"state": "Ready"
}'
# Jane: Level 1, Position 2 (second priority)
curl -X POST http://localhost:8000/v1/tiers \
-H "X-API-Key: demo" \
-H "Content-Type: application/json" \
-d '{
"queue": "support",
"agent": "jane@example.com",
"level": 1,
"position": 2,
"state": "Ready"
}'
# Bob: Level 2, Position 1 (overflow only)
curl -X POST http://localhost:8000/v1/tiers \
-H "X-API-Key: demo" \
-H "Content-Type: application/json" \
-d '{
"queue": "support",
"agent": "bob@example.com",
"level": 2,
"position": 1,
"state": "Ready"
}'
Step 4: Set Agents to Available
curl -X PUT http://localhost:8000/v1/agents/john@example.com/status \
-H "X-API-Key: demo" \
-H "Content-Type: application/json" \
-d '{"status": "Available"}'
curl -X PUT http://localhost:8000/v1/agents/jane@example.com/status \
-H "X-API-Key: demo" \
-H "Content-Type: application/json" \
-d '{"status": "Available"}'
curl -X PUT http://localhost:8000/v1/agents/bob@example.com/status \
-H "X-API-Key: demo" \
-H "Content-Type: application/json" \
-d '{"status": "Available"}'
Step 5: Test Call Flow
When a call comes in:
- Enters "support" queue
- Plays hold music
- System tries Level 1 agents:
- Rings John (Level 1, Position 1)
- If John doesn't answer in 10s, rings Jane (Level 1, Position 2)
- If no Level 1 agent available:
- After
tier_rule_wait_second(10s), escalates to Level 2 - Rings Bob (Level 2, Position 1)
- After
- Agent answers: Call connects
- Agent status: Changes to "In a queue call"
- After call ends: Agent enters wrap-up time (10s)
- Agent ready again: Status returns to "Available"
Call Distribution Flow
Monitoring and Metrics
Queue Metrics
Monitor queue health via:
# Real-time queue statistics
GET /v1/queues/{queue_name}/count
# Queue status (via XML-RPC)
GET /v1/queues/{queue_name}/status
# List all members (callers) in queue
GET /v1/members?queue=support
# List agents for queue
GET /v1/agents?queue=support
Key Metrics to Track
- Waiting: Callers currently in queue
- Trying: Calls attempting to connect to agents
- Answered: Active calls in progress
- Abandoned: Callers who hung up before answer
- Average Wait Time: Time from join to answer
- Agent Utilization: Percentage of time agents are on calls
Related Documentation
- System Overview - Architecture context
- Callcenter Direct API - Agents, tiers, members management
- Extension Management - SIP extensions for queues
- Helm Infrastructure - Pod orchestration
- Database Schema - Queue storage details
Troubleshooting
Queue Pod Won't Start
Symptoms: Pod stuck in Pending or CrashLoopBackOff
Check:
kubectl get pods -n client-demo-client | grep queue-{name}
kubectl logs -n client-demo-client freeswitch-queue-{name}
kubectl describe pod -n client-demo-client freeswitch-queue-{name}
Common Causes:
- Database connection failure (check ODBC config)
- Port conflict (ensure unique SIP/RTP ports)
- Resource limits too low (increase CPU/memory)
- ConfigMap not created (check
kubectl get configmap)
Agents Not Receiving Calls
Symptoms: Calls wait in queue, agents show "Available" but don't ring
Check:
-
Agent Status: Must be "Available" (not "Logged Out" or "On Break")
GET /v1/agents/{agent_name} -
Tier Assignment: Agent must be assigned to queue
GET /v1/tiers?queue={queue_name}&agent={agent_name} -
Tier State: Must be "Ready" (not "Standby")
PUT /v1/tiers/{queue}/{agent} -d '{"state": "Ready"}' -
Agent Contact: Verify SIP URI is correct
# Test if agent can be reached
# From FreeSWITCH CLI: originate sofia/gateway/registrar/agent-10720 &echo
Calls Not Entering Queue
Symptoms: Calls fail before entering queue
Check:
-
Queue Pod Running: Verify pod is healthy
kubectl get pods -n client-demo-client | grep queue-{name} -
SIP Registration: Queue should register with registrar
# From registrar CLI: sofia status profile internal reg -
Dialplan: Verify dialplan routes to queue
# Check dialplan routes caller to: callcenter {queue_name} -
Database Config: Verify queue exists in database
SELECT * FROM cc_queues WHERE name = 'queue_name';
High Wait Times
Symptoms: Callers wait too long before being answered
Solutions:
- Add More Agents: Increase agent count
- Adjust Tier Levels: Reduce
tier_rule_wait_secondfor faster escalation - Change Strategy: Try "ring-all" for faster answer
- Check Agent Status: Ensure agents are "Available" not "On Break"
- Monitor Agent Load: Check if agents are busy on other calls
Summary
Queue management is the core feature of Ominis Cluster Manager. Key takeaways:
✅ Queues are virtual waiting rooms for callers ✅ Agents are people who answer calls ✅ Tiers connect agents to queues with priority routing ✅ Members are callers waiting in queue ✅ Strategies determine how calls are distributed ✅ One pod per queue provides isolation, scaling, and fault tolerance ✅ Complete API for queue lifecycle management ✅ Real-time metrics for monitoring and optimization
With this foundation, you can build sophisticated call center workflows with predictable, scalable infrastructure.