Sorcery caching with missing ContactStatus AMI events

I’m running an Asterisk server with several thousand endpoints managed via a web interface. Currently, endpoint and aor are cached aggressively, but auth isn’t cached since credential resets need to take effect immediately.

I’ve optimized the caching by adding auth to cache and setting full_backend_cache=yes to reduce SQL traffic:

[res_pjsip]
endpoint/cache = memory_cache,object_lifetime_stale=1500,object_lifetime_maximum=1800,expire_on_reload=yes,full_backend_cache=yes
endpoint=realtime,ps_endpoints

auth/cache = memory_cache,object_lifetime_stale=1500,object_lifetime_maximum=1800,expire_on_reload=yes,full_backend_cache=yes
auth=realtime,ps_auths

aor/cache = memory_cache,object_lifetime_stale=1500,object_lifetime_maximum=1800,expire_on_reload=yes,full_backend_cache=yes
aor=realtime,ps_aors

However, I still need to manually run pjsip reload qualify aor <client> to get ContactStatus AMI events for newly created endpoints. (core reload also recovers these AMI events)

Is there a way to have Asterisk automatically emit these events without sending commands for newly created endpoints?

Ideally, the web interface just needs to stale updated entries in the Asterisk Sorcery cache.

Any way to achieve this?

No. You have to inform Asterisk.

Ok, so if I create 100 endpoints in the SQL db, I need to execute `pjsip reload qualify aor <client>`100 times. Once for every endpoint, correct? Or are there more efficient ways for this?

Also, is my assumption correct that caching endpoint, auth and aor in sorcery with leaving contactsin memory is the way how Asterisk can best handle a lot of endpoints?

Honestly the best way to handle a lot of endpoints is to scrap realtime and use .conf files and the default settings with reload as needed. It also eliminates the database as a point of failure within Asterisk itself. Caching helps, but does not eliminate that.

For realtime the contacts shouldn’t change that much, so persisting them in realtime or the normal astdb would also be fine. If you don’t care about them disappearing on restart, then memory is also fine.

And to the best of my recollection, there is only CLI functionality on a per-endpoint basis.

Ok, good reminder, I will consider this as this might be possible pretty elegant in our use-case!

I guess for the existing realtime use-case this is what is needed, or any better solutions?

There’s no better solutions.

Thanks for the quick responses!

Ok, tried to switch to a pure config file approach now. Basically put this into my pjsip.conf: #include conf.d/*.conf

This resulted in ~2000 config files with a total of ~30000 endpoints. This is a lot resulting in Asterisk needing ~30s to load this config.

I can reload the full config with pjsip reload taking again the ~30s.

Question: Is it possible to just reload single config files to speed this up on single changes?

No, there is no capability internally to reload just a specific file. If you’re truly configuring and doing 30,000 endpoints recognizable by a single Asterisk instance then you’re in uncharted territory over all.

The parsing/loading operation itself doesn’t block other aspects, so even if it takes 30 seconds during that time the system should operate as normal.

I’ve been testing the Asterisk cURL realtime backend as alternative. The idea was to put an in-memory cache (same node) between Asterisk and the database server. Turns out this doesn’t really provide an advantage.

I noticed without full_backend_cache=yes, Asterisk fires a multi query and then immediately follows up with individual single queries for each record it just loaded.

With full_backend_cache=yes on endpoint/auth/aor, Asterisk loads once via multi and then seems to operate from internal memory.

So for deployments with many endpoints, is full_backend_cache=yes an absolute must?
Without it, the single queries seem to be a big chance for pile up and problems.

So this would be the resulting sorcery config:

[res_pjsip]
endpoint/cache = memory_cache,object_lifetime_stale=1500,object_lifetime_maximum=1800,expire_on_reload=yes,full_backend_cache=yes
endpoint=realtime,ps_endpoints

auth/cache = memory_cache,object_lifetime_stale=1500,object_lifetime_maximum=1800,expire_on_reload=yes,full_backend_cache=yes
auth=realtime,ps_auths

aor/cache = memory_cache,object_lifetime_stale=1500,object_lifetime_maximum=1800,expire_on_reload=yes,full_backend_cache=yes
aor=realtime,ps_aors

At the scale you wish to operate at, yes a full backend cache is probably required.

Use the Sorcery AMI actions after inserting new rows, no reload needed:

Action: SorceryMemoryCachePopulateObject
Cache: <your_cache_name>
Object: aor
ObjectId: <new-aor-id>

Repeat for endpoint and auth. PopulateObject pulls the object from the realtime backend directly into the live cache, which starts the qualify timer and triggers ContactStatus events.

Also worth knowing:

  • SorceryMemoryCacheUpdateObject - mark an object stale (force refresh on next access)
  • SorceryMemoryCacheExpireObject - evict an object entirely

For your credential reset case, SorceryMemoryCacheExpireObject on the specific auth object is cleaner than leaving auth uncached entirely.