Hello
I'm doing a project where I need to route using dispatcher across multiple groups. i.e. when the customer makes a call, the "core" server makes a request to cgrates to get back a list of carriers that support that, and then want to work through them in order of preference.
e.g. the string we get back from cgrates via evapi might be "2,1,3". i.e. try all Group 2 destinations, then group 1, then group 3.
Each of these is then a dispatcher group (with multiple dispatcher routes in each group).
When the call then gets to the "Group 2" server that in turn is also using dispatcher to handle multiple destinations, and if all of those destinations fail, it returns a 503 to the "core", which is then meant to try "Group 1", and so on.
The documentation on this is a bit sparse, but what I think I am meant to do (at the core level) is use ds_select_routes to load up the list of groups (https://kamailio.org/docs/modules/5.3.x/modules/dispatcher.html#dispatcher.f...)
if(ds_select_routes("2=4;1=4;3=4", "d", "0")) { t_on_failure("REROUTE"); t_relay(); exit; }
and then in my failure_route, if the error code is 503 I call ds_next_domain, e.g.
failure_route[REROUTE] { if(t_check_status("503")) { if(ds_next_domain()) { t_on_failure("REROUTE"); t_relay(); exit; } } }
My problem is, that in applying theory to practice, I have ended up with a bunch of looping and it's not working right!
Does anyone have an example code for such a scenario?
many thanks peter
Hi Peter,
I've never used ds_select_routes(), but--taking a stab in the dark--it seems to me the principle would be something like:
----- modparam("dispatcher", "flags", 2)
route[...] { ...
if(!ds_select_routes("...", "d", "0")) { sl_send_reply("503", "No initial routes"); exit; }
t_on_failure("REROUTE");
if(!t_relay()) sl_reply_error(); }
failure_route[REROUTE] { if(t_is_canceled()) exit;
if(!ds_next_dst()) { send_reply("503", "Out of routes"); exit; }
t_on_failure("REROUTE"); t_relay(); } -----
A few important subtleties for which the documentation is indeed a bit sparse:
- "Failover" of any kind is made possible by storing a list of destinations, in ascending order of preference based on the dispatcher algorithm chosen (and the way all the groups are concatenated, in the particular case of ds_select_routes()), in a transaction-persistent data structure called an XAVP. But this behaviour is not enabled by default, and is enabled by setting bit 2 in the "flags" modparam to dispatcher, as in the example above.
- Because the chosen destination is being pushed into the destination URI (Kamailio-idiosyncratic next-hop URI) rather than the domain part of the Request URI (mode "d" for ds_select_routes()), you must use ds_next_dst() to iterate to the next step in the result set. ds_next_domain() would be appropriate only if the next destination to attempt were being stored in the "ruri", as is the case in the docs example but not in the code you posted. So, use ds_next_dst() in your failure_route instead.
-- Alex
On 9/4/20 5:53 PM, Peter Gradwell wrote:
Hello
I'm doing a project where I need to route using dispatcher across multiple groups. i.e. when the customer makes a call, the "core" server makes a request to cgrates to get back a list of carriers that support that, and then want to work through them in order of preference.
e.g. the string we get back from cgrates via evapi might be "2,1,3". i.e. try all Group 2 destinations, then group 1, then group 3.
Each of these is then a dispatcher group (with multiple dispatcher routes in each group).
When the call then gets to the "Group 2" server that in turn is also using dispatcher to handle multiple destinations, and if all of those destinations fail, it returns a 503 to the "core", which is then meant to try "Group 1", and so on.
The documentation on this is a bit sparse, but what I think I am meant to do (at the core level) is use ds_select_routes to load up the list of groups (https://kamailio.org/docs/modules/5.3.x/modules/dispatcher.html#dispatcher.f...)
if(ds_select_routes("2=4;1=4;3=4", "d", "0")) { t_on_failure("REROUTE"); t_relay(); exit; }
and then in my failure_route, if the error code is 503 I call ds_next_domain, e.g.
failure_route[REROUTE] { if(t_check_status("503")) { if(ds_next_domain()) { t_on_failure("REROUTE"); t_relay(); exit; } } }
My problem is, that in applying theory to practice, I have ended up with a bunch of looping and it's not working right!
Does anyone have an example code for such a scenario?
many thanks peter
Kamailio (SER) - Users Mailing List sr-users@lists.kamailio.org https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-users
Hi Alex, all
This was a super useful hint, many thanks.
For the archive's benefit, I had to tweak the failure_route a little bit. Essentially in my use case, the downstream carrier gateway is also using dispatcher, and returns me a 503 when it has no routes left. So I catch that error, then mark it as inactive, before trying to get the next route (without marking it inactive, I got looping).
modparam("dispatcher", "setid_pvname", "$var(setid)") #To tell cgrates what the dispatch destination is modparam("dispatcher","flags", 2) modparam("dispatcher", "xavp_dst", "_dsdst_")
failure_route[DISPATCH_FAILURE] {
if (t_is_canceled()) { xlog("CGRDISPATCHFAIL: is cancelled"); exit; }
if (t_check_status("503") or (t_branch_timeout() and !t_branch_replied())) {
ds_mark_dst("dp"); # set to inactive and probing
if(!ds_next_dst()) { xlog(Cannot set next destination in DISPATCH_FAILURE. Out of routes\n"); send_reply("503", "No destination - run out of routes"); exit; } else { xlog("CDR Set the next domain ok grp <$var(setid)> \n"); }
t_on_failure("DISPATCH_FAILURE");
route(RELAY);
} else { send_reply("503", "DISPATCH FAILURE for non 503 error downstream"); exit; }
}
The other thing I needed to do was to return the group id for the route that was finally used to make the call. I found that to do this, I needed to call ds_is_from_list just before I relayed the call
# try and find out which group it is if(ds_is_from_list("-1","2","$du")) { xlog("CGROUTERELAY Found grp $var(setid) for $du\n"); } else { xlog("CGROUTERELAY Tried to find group for $du but failed.\n"); }
xlog("CGRROUTERELAY: Sending call to ruri: $ru - du: <$du> grp: $var(setid)\n");
Cheers Peter
________________________________ From: sr-users sr-users-bounces@lists.kamailio.org on behalf of Alex Balashov abalashov@evaristesys.com Sent: 04 September 2020 23:23 To: sr-users@lists.kamailio.org sr-users@lists.kamailio.org Subject: Re: [SR-Users] Dispatcher / ds_select_routes
Hi Peter,
I've never used ds_select_routes(), but--taking a stab in the dark--it seems to me the principle would be something like:
----- modparam("dispatcher", "flags", 2)
route[...] { ...
if(!ds_select_routes("...", "d", "0")) { sl_send_reply("503", "No initial routes"); exit; }
t_on_failure("REROUTE");
if(!t_relay()) sl_reply_error(); }
failure_route[REROUTE] { if(t_is_canceled()) exit;
if(!ds_next_dst()) { send_reply("503", "Out of routes"); exit; }
t_on_failure("REROUTE"); t_relay(); } -----
A few important subtleties for which the documentation is indeed a bit sparse:
- "Failover" of any kind is made possible by storing a list of destinations, in ascending order of preference based on the dispatcher algorithm chosen (and the way all the groups are concatenated, in the particular case of ds_select_routes()), in a transaction-persistent data structure called an XAVP. But this behaviour is not enabled by default, and is enabled by setting bit 2 in the "flags" modparam to dispatcher, as in the example above.
- Because the chosen destination is being pushed into the destination URI (Kamailio-idiosyncratic next-hop URI) rather than the domain part of the Request URI (mode "d" for ds_select_routes()), you must use ds_next_dst() to iterate to the next step in the result set. ds_next_domain() would be appropriate only if the next destination to attempt were being stored in the "ruri", as is the case in the docs example but not in the code you posted. So, use ds_next_dst() in your failure_route instead.
-- Alex
On 9/4/20 5:53 PM, Peter Gradwell wrote:
Hello
I'm doing a project where I need to route using dispatcher across multiple groups. i.e. when the customer makes a call, the "core" server makes a request to cgrates to get back a list of carriers that support that, and then want to work through them in order of preference.
e.g. the string we get back from cgrates via evapi might be "2,1,3". i.e. try all Group 2 destinations, then group 1, then group 3.
Each of these is then a dispatcher group (with multiple dispatcher routes in each group).
When the call then gets to the "Group 2" server that in turn is also using dispatcher to handle multiple destinations, and if all of those destinations fail, it returns a 503 to the "core", which is then meant to try "Group 1", and so on.
The documentation on this is a bit sparse, but what I think I am meant to do (at the core level) is use ds_select_routes to load up the list of groups (https://kamailio.org/docs/modules/5.3.x/modules/dispatcher.html#dispatcher.f...)
if(ds_select_routes("2=4;1=4;3=4", "d", "0")) { t_on_failure("REROUTE"); t_relay(); exit; }
and then in my failure_route, if the error code is 503 I call ds_next_domain, e.g.
failure_route[REROUTE] { if(t_check_status("503")) { if(ds_next_domain()) { t_on_failure("REROUTE"); t_relay(); exit; } } }
My problem is, that in applying theory to practice, I have ended up with a bunch of looping and it's not working right!
Does anyone have an example code for such a scenario?
many thanks peter
Kamailio (SER) - Users Mailing List sr-users@lists.kamailio.org https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-users
-- Alex Balashov | Principal | Evariste Systems LLC
Tel: +1-706-510-6800 / +1-800-250-5920 (toll-free) Web: http://www.evaristesys.com/, http://www.csrpswitch.com/
_______________________________________________ Kamailio (SER) - Users Mailing List sr-users@lists.kamailio.org https://lists.kamailio.org/cgi-bin/mailman/listinfo/sr-users
Hello Peter,
Glad you got it working!
However, I'm not clear on why you should be manually marking anything as inactive. If you are using algorithm 4, you should not be getting any looping -- once you've burned through the set gateways returned by dispatcher, ds_next_dst() should fail and you should fall out of the failure_route, returning a 503 to the caller.
-- Alex