Documentation |
Documentation -> Manuals -> Manual devel -> Asynchronous StatementsThis page has been visited 390 times. Pages for other versions: devel 3.5 3.4 Older versions: 3.3 3.2 3.1 3.0 2.4 2.3 2.2 2.1
Table of Content (hide) 1. DescriptionAsynchronous statements are one of the key features of OpenSIPS 2.X. One of the main reasons to use them is that they allow the performance of the OpenSIPS script to scale with a high number of requests per second even when doing blocking I/O operations such as MySQL queries, exec commands or HTTP requests.
2. Serial asynchronous operations, async() 🔗The async() statement of the OpenSIPS script can be used in situations where the script writer both needs to perform blocking I/O and also depends on the result of this operation. Some example scenarios:
2.1 RequirementsThe async() statement depends on the transaction module (tm) - it must be loaded. The SIP transaction will be automatically and transparently created when an async operation is started, if necessary. This transaction contains all the necessary information to suspend script execution (e.g. it stores the updated SIP message, along with all $avp variables). 2.2 Script syntax and usageUsage is straightforward: if your blocking function supports asynchronous mode (read the module documentation for this), then you can just throw it in the following function call: async(blocking_function(...), resume_route [,timeout]); Note that resume_route must be a simple route.
route { /* preparation code */ ... async(avp_db_query("SELECT credit FROM users WHERE uid='$avp(uid)'", "$avp(credit)"), resume_credit); /* script execution is paused right away! */ } route [resume_credit] { if ($rc < 0) { xlog("error $rc in avp_db_query()\n"); exit; } xlog("Credit of user $avp(uid) is $avp(credit)\n"); ... t_relay(); }
Ignored data (not available anymore in resume route)
3. Parallel asynchronous operations, launch() 🔗The launch() statement of the OpenSIPS script can be used in situations where the script writer needs to perform blocking I/O, but does not depend on the result of this operation in order to continue the current SIP routing decision flow. Some example scenarios:
3.1 Script syntax and usageSimilarly to the async() statement, if your blocking function supports asynchronous mode (read the module documentation for this), then you can just throw it in the following function calls: launch(blocking_function(...)); or launch(blocking_function(...), report_route); route[report_route] {} or launch(blocking_function(...), report_route, "Something with $var(xx) to be passed to report route"); route[report_route] { xlog("received as input the <$param(1)> string\n"); } Note that report_route must be a simple route.
route { /* preparation code */ ... # send a push notification asynchronously, in parallel launch(exec("/usr/local/bin/send-google-pn.py"), pn_counter); t_relay(); } route [pn_counter] { if ($rc < 0) { xlog("error $rc in pn script!\n"); update_stat("pn-failure", "1"); exit; } update_stat("pn-success", "1"); }
Ignored data (not available anymore in report route)
4. List of async functions 🔗The following functions may also be called asynchronously: The async implementation is not limited to the above functions, but these are the first ones migrated to async support. More I/O related functions will be ported to the async support. 5. Limitations 🔗5.1 Async Engine CompatibilityThe async engine is heavily dependent on non-blocking I/O features exposed by the underlying libraries -- a blocking I/O operation, such as an HTTP or an SQL query can only be made asynchronous if the library additionally provides both:
5.2 TCP Connect IssuesAlthough they provide async functionality, some libraries only do this for the "transfer" part of the I/O operation, and NOT the initial TCP connect. Consequently, on some corner-case scenarios (e.g. the TCP connect hangs due to an unresponsive server, an in-between firewall which drops packets instead of rejecting them, etc.) the async operation may actually block!
Mitigation: depending on your specific setup, you may be severely impacted by these blocking TCP connects or hardly at all. For the former case, we suggest forking external processes responsible for your blocking operations and invoke them asynchronously, using constructs such as:
or
5.3 Allowed Routes 🔗Since the async operations are tightly coupled with the transactional engine, they can only be performed in routes where a SIP transaction is present and is awaiting completion:
On the other hand, the launch statement should work from any route, as it is not dependent on the underlying SIP transaction. |