Attach cleanup to the channel that owns it
A hangup handler is a Gosub-style target stored on one channel. Asterisk runs the channel's associated handlers when that channel hangs up. The handler therefore belongs to a channel, not automatically to the whole customer conversation, bridge or every leg sharing a linked identifier.
Name the resource being cleaned up, the exact channel that owns it, the point where the handler is installed and the evidence expected after teardown. A handler on the caller does not prove that an outbound callee, Local-channel half or transferred destination has the same stack.
Use push, pop and wipe as different stack operations
Asterisk exposes write-only CHANNEL() items for hangup handlers. hangup_handler_push adds a target, hangup_handler_pop removes the most recently added target and may replace it, and hangup_handler_wipe removes the full stack and may install one replacement. They are not interchangeable reset commands.
Prefer a fully qualified context, extension and priority so later dialplan movement does not obscure the stored destination. This inert example records one label and returns; it performs no network request, file deletion or external call.
[rw-entry]
exten => 7101,1,NoOp(Push bounded teardown handler)
same => n,Set(CHANNEL(hangup_handler_push)=rw-cleanup,s,1(${UNIQUEID}))
same => n,Hangup()
[rw-cleanup]
exten => s,1,NoOp(Teardown marker for ${ARG1})
same => n,Return()Expect last-in, first-out execution
Multiple handlers form a stack. Asterisk documents that the most recently pushed handler executes first, followed by earlier entries. Record every push, pop and wipe with the same channel identifier; configuration order in a file is not enough when conditional branches manipulate the stack at runtime.
Each handler is a subroutine and should return explicitly. A missing return, invalid target or long-running application can interrupt the intended sequence. Do not add a second copy merely because the downstream effect is absent; first prove whether the first target was stored, invoked and completed.
Do not depend on order relative to the h extension
Asterisk documents the relative execution order between hangup handlers and the dialplan h extension as undefined. Adding a handler from the h extension or while another hangup handler is running is also undefined behavior. Design independent, idempotent cleanup rather than a hidden dependency on which mechanism runs first.
Keep one authoritative owner for each side effect. If both an h extension and a handler write the same external record, mark the operation with a stable call and channel key so a retry or different execution order does not create a duplicate.
Keep the hangup path short and local
Hangup handlers execute in the call leg's teardown sequence. Asterisk warns that they should run quickly because channel protocols may be unable to tolerate excessive delay completing hangup. Avoid treating a slow HTTP request, database lock, DNS lookup or remote queue as harmless cleanup.
Capture minimal local evidence, perform bounded idempotent work and move nonessential processing to an asynchronous system with its own delivery proof. A returned handler establishes only dialplan completion; it does not prove that a remote consumer committed a record.
Prove stack lifecycle, handler run and final hangup separately
Before hangup, inspect the intended channel with the documented core show hanguphandlers commands. AMI can expose HangupHandlerPush, HangupHandlerPop and HangupHandlerRun events, each carrying channel identifiers and the stored handler string. Correlate those with the later Hangup event, cause and any CDR or CEL records.
Test normal completion, caller cancellation, callee rejection, no answer, transfer and administrative hangup only where authorized. Verify LIFO order, explicit returns, bounded duration, one durable side effect and channel cleanup. No PBX, dialplan, channel, handler stack, event, record, endpoint, call or teardown path was inspected or tested for this guide.
Do not use teardown to replace an earlier final response
PJSIPHangup() selects a final incoming response before answer and terminates dialplan execution. The paired guide keeps that transaction action separate from bounded hangup-handler cleanup.
Do not make hangup cleanup the normal unlock path
The lock diagnostic uses automatic channel-destruction release as a final boundary while requiring explicit release after normal work.
Do not merge exception handling with hangup cleanup
The exception guide treats e, explicit application status and channel cleanup as separate control paths with deliberate final outcomes.
Do not turn teardown into an implicit success path
The ODBC transaction guide retains rollback-on-channel-destruction as the documented default and treats forcecommit as an explicit risk decision.
Do not confuse periodic hook teardown with a hangup handler
The periodic-hook diagnostic correlates owner lifetime, hook ID, asynchronous run and buffered audio before assigning late sound to teardown.
A channel can end before its target epoch
The WaitUntil guide treats HANGUP as a channel-lifecycle outcome and keeps any required cleanup under a separate contract.
Do not replace bridge-exit evidence with cleanup
The Bridge diagnostic correlates first leave, hangup, F(), x, status and surviving-channel dialplan before adding a handler.
Sources & applicability
Primary references for the technical details above. Operational examples and planning checklists are VoIP.info editorial guidance.
- Asterisk hangup handlers ↗
- Asterisk 22 CHANNEL function reference ↗
- Asterisk 22 HangupHandlerPush AMI event ↗
- Asterisk 22 HangupHandlerPop AMI event ↗
- Asterisk 22 HangupHandlerRun AMI event ↗
- Asterisk hangup-cause overview ↗
- Asterisk 22 Hangup AMI event ↗
- Asterisk 22 Return application reference ↗
- Asterisk PJSIPHangup dialplan application ↗
- Asterisk Hangup dialplan application ↗
- Asterisk hangup-cause mappings ↗
- RFC 3261: SIP response and transaction semantics ↗
- Asterisk LOCK dialplan function ↗
- Asterisk TRYLOCK dialplan function ↗
- Asterisk UNLOCK dialplan function ↗
- Asterisk 22 SHARED dialplan function ↗
- Asterisk global variables basics ↗
- Asterisk special dialplan extensions ↗
- Asterisk 23 RaiseException application ↗
- Asterisk 23 EXCEPTION function ↗
- Asterisk 23 TryExec application ↗
- Asterisk database transactions ↗
- Asterisk latest ODBC transaction function ↗
- Asterisk latest ODBC_Commit application ↗
- Asterisk latest ODBC_Rollback application ↗
- Asterisk func_odbc.conf sample ↗
- Asterisk res_odbc.conf sample ↗
- Asterisk Configuring res_odbc ↗
- Asterisk 23 PERIODIC_HOOK function ↗
- Asterisk 22 PERIODIC_HOOK function ↗
- Asterisk 20 PERIODIC_HOOK function ↗
- Asterisk Playback application ↗
- Asterisk CHANNEL function ↗
- Asterisk 23 WaitUntil application ↗
- Asterisk 22 WaitUntil application ↗
- Asterisk 23 TIMEOUT function ↗
- Asterisk 23 STRFTIME function ↗
- Asterisk 23 STRPTIME function ↗
- Asterisk 23 Bridge application ↗
- Asterisk 22 Bridge application ↗
- Asterisk Bridge application overview ↗
- Asterisk 23 CHANNELS function ↗
- Asterisk ARI bridge overview ↗
Examples require adaptation to your topology. No live PBX or hardware testing is claimed.