Skip to content

PJSIP qualify: configurable consecutive failures and faster retry after timeout #87

Description

@phoneben

Is your feature or improvement request related to a problem? Please describe.

Yes.

Currently, a single failed PJSIP qualification can mark a contact as unavailable.

For production PBX-to-PBX trunks, this can be too aggressive. A single delayed or lost SIP OPTIONS request can temporarily mark the trunk Unreachable, even though the remote PBX is otherwise healthy.

This can immediately affect routing and cause real calls to fail.

For example, during one short qualification issue I saw:

Contact pbx07/... is now Unreachable

and shortly afterward the contact became reachable again.

During that period, calls failed because Asterisk considered the destination unavailable:

[2026-09-09 13:48:07] VERBOSE[28215][C-002303d0] pbx.c:
Executing [~~s~~@dialqueue:196] Dial("PJSIP/fs4-new-002385f4",
"PJSIP/QUEUE-7863@pbx07,,gb(pjsip_header,setpjsipheader,1)") in new stack

[2026-09-09 13:48:07] NOTICE[28215][C-002303d0] app_dial.c:
Unable to create channel of type 'PJSIP' (cause 3 - No route to destination)

[2026-09-09 13:48:07] VERBOSE[28215][C-002303d0] app_dial.c:
Everyone is busy/congested at this time (1:0/0/1)

The trunk itself was not permanently down. A transient OPTIONS failure was enough to temporarily remove it as a usable destination.

The current workaround is to lower qualify_frequency, for example to 10-12 seconds, so recovery happens faster.

However, that means sending OPTIONS every 10-12 seconds continuously to every healthy trunk just to reduce the impact of a rare failure.

I would prefer to normally qualify every 30 seconds, while having more aggressive retries only after a qualification failure.

Describe the solution you'd like

I would like two optional PJSIP AoR qualification settings.

1. Consecutive qualification failures before marking a contact unavailable

Something conceptually similar to FreeSWITCH ping-min.

For example:

qualify_frequency=30
qualify_timeout=3
qualify_failures=3

Behavior:

OPTIONS failure #1 -> remain Available
OPTIONS failure #2 -> remain Available
OPTIONS failure #3 -> become Unavailable

Any successful qualification would reset the consecutive failure counter.

The default could remain:

qualify_failures=1

so existing installations keep the current behavior.

2. Faster retry interval after a qualification failure

A second setting could control how quickly PJSIP retries after a timeout:

qualify_retry_interval=2

Example configuration:

qualify_frequency=30
qualify_timeout=3
qualify_failures=3
qualify_retry_interval=2

Normal operation would remain:

00s OPTIONS -> success
30s OPTIONS -> success
60s OPTIONS -> success

If a qualification fails:

90s OPTIONS -> timeout
    failure #1, remain Available

92s retry -> timeout
    failure #2, remain Available

94s retry -> timeout
    failure #3, mark Unavailable

If one of the retries succeeds:

90s OPTIONS -> timeout
92s retry -> success

failure counter resets
contact remains Available
normal 30-second qualification interval resumes

This would allow a relatively long normal qualification interval while still detecting a genuinely failed trunk very quickly.

It would also prevent one transient packet loss or short scheduling/network delay from immediately removing an active production trunk.

Describe alternatives you've considered

The main alternative is lowering qualify_frequency.

For example:

qualify_frequency=10

or even lower.

This helps because if a contact is temporarily marked unavailable, another qualification occurs relatively soon.

However, it has two disadvantages:

  1. It creates unnecessary OPTIONS traffic during normal healthy operation.
  2. It does not solve the main issue: one failed qualification can still immediately mark the contact unavailable.

Another option is increasing qualify_timeout, but that solves a different problem. It allows a slow response more time to arrive, but does not protect against a single genuinely lost OPTIONS packet.

Using only a consecutive-failure threshold also has a problem.

For example:

qualify_frequency=30
qualify_failures=3

could take close to 90 seconds to determine that a genuinely dead trunk is unavailable.

That is why I think the failure threshold and fast retry interval are most useful together.

Additional context

The intended use case is primarily PBX-to-PBX and other important SIP trunks.

For these trunks, there are two competing requirements:

  • Do not mark a healthy trunk unavailable because of one transient qualification failure.
  • Do not wait 60-90 seconds to detect a trunk that is genuinely down.

The combination of:

qualify_frequency=30
qualify_timeout=3
qualify_failures=3
qualify_retry_interval=2

would provide both.

Healthy contact:

OPTIONS ---------------- 30 seconds ---------------- OPTIONS

Failure condition:

OPTIONS timeout
   |
   +-- 2 sec --> retry fails
                   |
                   +-- 2 sec --> retry fails
                                   |
                                   +--> Unavailable

This would reduce unnecessary qualification traffic during normal operation while making failure handling both safer and faster.

The exact option names are only suggestions; the important behavior is:

  • configurable consecutive failures before changing contact status to unavailable;
  • a separate accelerated qualification interval while the contact is in a failure/retry state;
  • successful qualification resets the failure count and restores the normal qualification interval;
  • defaults preserve the current behavior.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions