recording-daemon: lifecycle notification events#2142
Open
goolanceman wants to merge 2 commits into
Open
Conversation
goolanceman
marked this pull request as ready for review
July 18, 2026 17:53
Extend rtpengine-recording HTTP/command notifications beyond the historical finished-only path so operators can track call and stream recording lifecycle. Events (notify-events CSV, default: finished): opened, started, finished, discarded, failed, call-started, call-finished, call-discarded New options: notify-events, notify-json, notify-no-metadata, notify-command-format, notify-queue-limit. Docs/conf only document the new notify options; upstream storage (S3/GCS/output-storage) docs are left unchanged. Backward compatible: default mask is finished only. Includes unit tests and Docker e2e smoke harness.
goolanceman
force-pushed
the
recording-notify-lifecycle
branch
from
July 18, 2026 18:10
a4ccba2 to
fd097da
Compare
notify_setup must not require notify-uri/notify-command: the same thread pool backs S3, GCS and DB notif_action_t work. Also leave object_name to action cleanup to avoid double-free on those paths.
rfuchs
reviewed
Jul 19, 2026
rfuchs
left a comment
Member
There was a problem hiding this comment.
This is all AI generated, isn't it
Comment on lines
-150
to
234
|
|
||
| static void *notify_timer(void *p) { | ||
| pthread_mutex_lock(&timer_lock); | ||
|
|
||
| // notify_timers being NULL acts as our shutdown flag | ||
| while (notify_timers) { | ||
| ilog(LOG_DEBUG, "Notification timer thread looping"); | ||
|
|
||
| // grab first entry in list, check retry time, sleep if it's in the future | ||
|
|
||
| notif_req_t *first = rtpe_g_tree_first(notify_timers); | ||
| if (!first) { | ||
| ilog(LOG_DEBUG, "No scheduled notification retries, sleeping"); | ||
| pthread_cond_wait(&timer_cond, &timer_lock); | ||
| continue; | ||
| } | ||
| int64_t now = now_us(); | ||
| if (now < first->retry_time) { | ||
| ilog(LOG_DEBUG, "Sleeping until next scheduled notification retry in %" PRId64 " seconds", | ||
| (first->retry_time - now) / 1000000L); | ||
| cond_timedwait(&timer_cond, &timer_lock, first->retry_time); | ||
| continue; | ||
| } | ||
|
|
||
| // first entry is ready to run | ||
|
|
||
| g_tree_remove(notify_timers, first); | ||
| ilog(LOG_DEBUG, "Notification retry for '%s%s%s' is scheduled now", FMT_M(first->name)); | ||
| g_thread_pool_push(notify_threadpool, first, NULL); | ||
| } | ||
|
|
||
| // clean up | ||
|
|
||
| pthread_mutex_unlock(&timer_lock); | ||
| pthread_mutex_destroy(&timer_lock); | ||
| pthread_cond_destroy(&timer_cond); | ||
|
|
||
| return NULL; | ||
| } |
Member
There was a problem hiding this comment.
Why remove the debug log messages and the existing comments?
Comment on lines
-193
to
242
|
|
||
| if (a->retry_time < b->retry_time) | ||
| return -1; | ||
| if (a->retry_time > b->retry_time) | ||
| return 1; | ||
| if (a < b) | ||
| return -1; | ||
| if (a > b) | ||
| return 1; | ||
| if (a->retry_time < b->retry_time) return -1; | ||
| if (a->retry_time > b->retry_time) return 1; | ||
| if (a < b) return -1; | ||
| if (a > b) return 1; | ||
| return 0; |
Member
There was a problem hiding this comment.
Don't lump in reformats in the same commit
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Extends
rtpengine-recordingnotifications from the historical finished-only path to a configurable call/stream lifecycle event set, while remaining backward compatible.Events (
notify-eventsCSV)openedrecording_file_openedstartedrecording_startedfinished(default)recording_finisheddiscardedrecording_discardedfailedrecording_failedcall-startedcall_recording_startedcall-finishedcall_recording_finishedcall-discardedcall_recording_discardedallDefault remains
finishedonly so existing deployments are unchanged.New options
notify-events— CSV list (defaultfinished)notify-json— POST JSON body via json-glibnotify-no-metadata— omit call metadata from payloadsnotify-command-format—legacy|extended|json-envnotify-queue-limit— bound non-terminal queue depth (default 1000;0= unlimited). Terminal events are always accepted.Design
notif_action_t/notif_req_t) andlib/http.chelpersnotify_events.c(shared with unit tests)output.c; call hooks inmetafile.c/packet.cnotif_reqbefore queueing (workers never touch live objects)Tests
t/test-notify-events.c— PASSt/notify_e2e/temp Python HTTP receiver + metafile lifecycle — E2E_NOTIFY_OKcall_recording_finishedwith JSON body + lifecycle headersDocs
docs/rtpengine-recording.mdetc/rtpengine-recording.confExample
Compatibility
notify-commandargv (path,db_id) preserved whennotify-command-format=legacyReviewer notes / BC details
Scope
s3.c,gcs.c,db.c) is not modified; these still use the sharednotif_action_tpool.Thread pool / storage safety
notify_setup()now only gates onnotify_threads > 0and always starts the shared thread pool when enabled.notif_action_tusers continue to work even whennotify-uri/notify-commandare not configured.Memory safety
req_free_fields()now only frees lifecycle snapshot strings (call/output/tag/error/JSON), leaving action-owned fields (headers, argv/envp, content,object_name, etc.) to the relevantaction->cleanup().req->object_nameon the S3/GCS paths, which already free it in their own cleanup.Finished-only backward compatibility
finishedevent is emitted (via the new event mask helpers).notify-commandargv layout inlegacymode.X-Recording-Event,X-Recording-Status,X-Recording-Event-Time, plus media/size/duration where available) and slightly richerX-Recording-Full-File-Namesemantics (prefers the actual on-diskfilenamewhere available).Full-File-Name.