Struct QueueManager

Source
pub struct QueueManager { /* private fields */ }
Expand description

§Call Queue Manager

The central coordinator for all call queuing operations in the call center. Manages multiple named queues, coordinates call assignment, and provides comprehensive queue statistics and monitoring.

§Key Features

  • Multi-Queue Management: Handles multiple named queues simultaneously
  • Priority-Based Queuing: Automatic priority ordering within queues
  • Assignment Tracking: Prevents race conditions during call assignment
  • Comprehensive Statistics: Real-time queue performance metrics
  • Expiration Management: Automatic cleanup of expired calls

§Thread Safety

QueueManager is designed for single-threaded use within the call center engine. For multi-threaded access, wrap in appropriate synchronization primitives.

§Examples

§Basic Usage

use rvoip_call_engine::queue::{QueueManager, QueuedCall};
use rvoip_session_core::SessionId;
 
let mut queue_manager = QueueManager::new();
 
// Create department queues
queue_manager.create_queue("support".to_string(), "Technical Support".to_string(), 50)?;
queue_manager.create_queue("sales".to_string(), "Sales Team".to_string(), 30)?;
 
// Queue a high-priority call
let urgent_call = QueuedCall {
    session_id: SessionId::new(),
    caller_id: "+1-555-0123".to_string(),
    priority: 1,
    queued_at: chrono::Utc::now(),
    estimated_wait_time: Some(30),
    retry_count: 0,
};
 
queue_manager.enqueue_call("support", urgent_call)?;
 
// Get next call for an agent
if let Some(call) = queue_manager.dequeue_for_agent("support")? {
    println!("Assigning call to agent: {}", call.session_id);
}

Implementations§

Source§

impl QueueManager

Source

pub fn new() -> Self

Create a new queue manager

Initializes an empty queue manager ready to handle call queuing operations. No queues are created by default - use create_queue to add queues.

§Examples
use rvoip_call_engine::queue::QueueManager;
 
let queue_manager = QueueManager::new();
assert_eq!(queue_manager.total_queued_calls(), 0);
Source

pub fn get_queue_ids(&self) -> Vec<String>

Get all queue IDs

Returns a list of all queue identifiers currently managed by this queue manager. Useful for iterating over all queues or administrative operations.

§Returns

Vector of queue ID strings.

§Examples
use rvoip_call_engine::queue::QueueManager;
 
let mut queue_manager = QueueManager::new();
queue_manager.create_queue("support".to_string(), "Support".to_string(), 50)?;
queue_manager.create_queue("sales".to_string(), "Sales".to_string(), 30)?;
 
let queue_ids = queue_manager.get_queue_ids();
assert_eq!(queue_ids.len(), 2);
assert!(queue_ids.contains(&"support".to_string()));
assert!(queue_ids.contains(&"sales".to_string()));
Source

pub fn create_queue( &mut self, queue_id: String, name: String, max_size: usize, ) -> Result<()>

Create a new queue

Adds a new named queue to the queue manager with the specified configuration. Each queue has its own capacity limits and policies.

§Arguments
  • queue_id - Unique identifier for the queue
  • name - Human-readable name for the queue
  • max_size - Maximum number of calls allowed in this queue
§Returns

Ok(()) if queue was created successfully, error if queue already exists.

§Examples
use rvoip_call_engine::queue::QueueManager;
 
let mut queue_manager = QueueManager::new();
 
// Create queues for different departments
queue_manager.create_queue("support".to_string(), "Technical Support".to_string(), 50)?;
queue_manager.create_queue("sales".to_string(), "Sales Team".to_string(), 30)?;
queue_manager.create_queue("billing".to_string(), "Billing Department".to_string(), 20)?;
 
// Verify queues were created
assert_eq!(queue_manager.get_queue_ids().len(), 3);
§Production Notes
  • Choose appropriate max_size values based on expected call volume
  • Queue IDs should follow a consistent naming convention
  • Consider using department codes or service types as queue IDs
Source

pub fn is_call_queued(&self, queue_id: &str, session_id: &SessionId) -> bool

Check if a call is already in the queue

Determines whether a specific call (identified by session ID) is already present in the specified queue. Useful for preventing duplicate queueing operations.

§Arguments
  • queue_id - Queue to check
  • session_id - Session ID of the call to check
§Returns

true if the call is already queued, false otherwise.

§Examples
use rvoip_call_engine::queue::{QueueManager, QueuedCall};
use rvoip_session_core::SessionId;
 
 
let session_id = SessionId::new();
 
// Initially not queued
assert!(!queue_manager.is_call_queued("support", &session_id));
 
// Add call to queue
let call = QueuedCall {
    session_id: session_id.clone(),
    caller_id: "+1-555-1234".to_string(),
    priority: 5,
    queued_at: chrono::Utc::now(),
    estimated_wait_time: Some(120),
    retry_count: 0,
};
queue_manager.enqueue_call("support", call)?;
 
// Now it's queued
assert!(queue_manager.is_call_queued("support", &session_id));
Source

pub fn is_call_being_assigned(&self, session_id: &SessionId) -> bool

Check if a call is being assigned

Determines whether a call is currently in the process of being assigned to an agent. This prevents race conditions where a call might be assigned to multiple agents simultaneously.

§Arguments
  • session_id - Session ID of the call to check
§Returns

true if the call is being assigned, false otherwise.

§Examples
use rvoip_call_engine::queue::QueueManager;
use rvoip_session_core::SessionId;
 
let mut queue_manager = QueueManager::new();
let session_id = SessionId::new();
 
// Initially not being assigned
assert!(!queue_manager.is_call_being_assigned(&session_id));
 
// Mark as being assigned
queue_manager.mark_as_assigned(&session_id);
assert!(queue_manager.is_call_being_assigned(&session_id));
 
// Mark as no longer being assigned
queue_manager.mark_as_not_assigned(&session_id);
assert!(!queue_manager.is_call_being_assigned(&session_id));
Source

pub fn enqueue_call( &mut self, queue_id: &str, call: QueuedCall, ) -> Result<usize>

Enqueue a call

Adds a call to the specified queue with automatic priority ordering. Higher priority calls (lower priority numbers) are placed ahead of lower priority calls in the queue.

§Arguments
  • queue_id - Target queue for the call
  • call - Call information including priority and metadata
§Returns

Returns the position in the queue where the call was inserted (0-based), or an error if the operation failed.

§Examples
use rvoip_call_engine::queue::{QueueManager, QueuedCall};
use rvoip_session_core::SessionId;
 
 
// Add a normal priority call
let normal_call = QueuedCall {
    session_id: SessionId::new(),
    caller_id: "+1-555-1234".to_string(),
    priority: 5,
    queued_at: chrono::Utc::now(),
    estimated_wait_time: Some(120),
    retry_count: 0,
};
let position1 = queue_manager.enqueue_call("support", normal_call)?;
assert_eq!(position1, 0); // First call, position 0
 
// Add a high priority call (should jump to front)
let urgent_call = QueuedCall {
    session_id: SessionId::new(),
    caller_id: "+1-555-VIP1".to_string(),
    priority: 1, // Higher priority
    queued_at: chrono::Utc::now(),
    estimated_wait_time: Some(30),
    retry_count: 0,
};
let position2 = queue_manager.enqueue_call("support", urgent_call)?;
assert_eq!(position2, 0); // Jumped to front due to higher priority
§Errors
  • CallCenterError::Queue - Queue is full or other queue-related error
  • CallCenterError::NotFound - Specified queue doesn’t exist
§Behavior
  • Prevents duplicate queueing of the same call
  • Prevents queueing calls that are currently being assigned
  • Enforces queue capacity limits
  • Maintains priority ordering automatically
Source

pub fn mark_as_assigned(&mut self, session_id: &SessionId)

Mark a call as being assigned (to prevent duplicate processing)

Marks a call as currently being assigned to an agent to prevent race conditions where the same call might be processed by multiple threads or assigned to multiple agents.

§Arguments
  • session_id - Session ID of the call being assigned
§Examples
use rvoip_call_engine::queue::QueueManager;
use rvoip_session_core::SessionId;
 
let mut queue_manager = QueueManager::new();
let session_id = SessionId::new();
 
// Mark call as being assigned
queue_manager.mark_as_assigned(&session_id);
 
// Verify it's marked
assert!(queue_manager.is_call_being_assigned(&session_id));
§Usage Pattern

This method should be called when a call is dequeued and assignment begins. If assignment succeeds, the call remains dequeued. If assignment fails, call mark_as_not_assigned to allow re-queuing.

Source

pub fn mark_as_not_assigned(&mut self, session_id: &SessionId)

Mark a call as no longer being assigned (on failure)

Removes the assignment lock on a call, allowing it to be processed again. This should be called when call assignment fails and the call should be made available for re-queuing or re-assignment.

§Arguments
  • session_id - Session ID of the call to unlock
§Examples
use rvoip_call_engine::queue::QueueManager;
use rvoip_session_core::SessionId;
 
let mut queue_manager = QueueManager::new();
let session_id = SessionId::new();
 
// Mark as assigned, then unmark due to failure
queue_manager.mark_as_assigned(&session_id);
queue_manager.mark_as_not_assigned(&session_id);
 
// Verify it's no longer marked
assert!(!queue_manager.is_call_being_assigned(&session_id));
§Usage Pattern
// Dequeue call (automatically marked as assigned)
if let Some(call) = queue_manager.dequeue_for_agent("support")? {
    // Attempt to assign to agent
    match assign_to_agent(&call).await {
        Ok(_) => {
            // Success - call remains dequeued and assigned
            info!("Call assigned successfully");
        }
        Err(e) => {
            // Failure - allow re-queuing
            queue_manager.mark_as_not_assigned(&call.session_id);
            warn!("Assignment failed: {}", e);
        }
    }
}
Source

pub fn dequeue_for_agent( &mut self, queue_id: &str, ) -> Result<Option<QueuedCall>>

Dequeue the next call for an agent

Removes and returns the highest priority call from the specified queue that is not currently being assigned. The returned call is automatically marked as being assigned to prevent duplicate processing.

§Arguments
  • queue_id - Queue to dequeue from
§Returns
  • Ok(Some(QueuedCall)) - Call was successfully dequeued
  • Ok(None) - No calls available in the queue
  • Err(...) - Queue doesn’t exist or other error
§Examples
use rvoip_call_engine::queue::{QueueManager, QueuedCall};
use rvoip_session_core::SessionId;
 
 
// Add some calls to the queue
let call1 = QueuedCall {
    session_id: SessionId::new(),
    caller_id: "+1-555-1234".to_string(),
    priority: 5, // Normal priority
    queued_at: chrono::Utc::now(),
    estimated_wait_time: Some(120),
    retry_count: 0,
};
queue_manager.enqueue_call("support", call1)?;
 
let urgent_call = QueuedCall {
    session_id: SessionId::new(),
    caller_id: "+1-555-VIP1".to_string(),
    priority: 1, // High priority
    queued_at: chrono::Utc::now(),
    estimated_wait_time: Some(30),
    retry_count: 0,
};
queue_manager.enqueue_call("support", urgent_call)?;
 
// Dequeue - should get the high priority call first
if let Some(call) = queue_manager.dequeue_for_agent("support")? {
    assert_eq!(call.priority, 1); // High priority call came first
    assert_eq!(call.caller_id, "+1-555-VIP1");
     
    // Call is now marked as being assigned
    assert!(queue_manager.is_call_being_assigned(&call.session_id));
}
§Behavior
  • Returns highest priority call (lowest priority number)
  • Skips calls that are already being assigned
  • Automatically marks returned call as being assigned
  • Maintains queue statistics and logging
Source

pub fn remove_expired_calls(&mut self) -> Vec<SessionId>

Remove expired calls from all queues

Source

pub fn total_queued_calls(&self) -> usize

Get total number of queued calls across all queues

Source

pub fn get_queue_stats(&self, queue_id: &str) -> Result<QueueStats>

Get queue statistics

Source

pub fn cleanup_stuck_assignments( &mut self, timeout_seconds: u64, ) -> Vec<SessionId>

Clean up calls that have been stuck in “being assigned” state

Source

pub fn force_unmark_assigned(&mut self, session_id: &SessionId) -> bool

Force remove a call from being assigned state

Trait Implementations§

Source§

impl Default for QueueManager

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<'a, T, E> AsTaggedExplicit<'a, E> for T
where T: 'a,

Source§

fn explicit(self, class: Class, tag: u32) -> TaggedParser<'a, Explicit, Self, E>

Source§

impl<'a, T, E> AsTaggedImplicit<'a, E> for T
where T: 'a,

Source§

fn implicit( self, class: Class, constructed: bool, tag: u32, ) -> TaggedParser<'a, Implicit, Self, E>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,