Summary:ASTERISK-12608: Multiple agents answering a call.
Reporter:Atis Lezdins (atis)Labels:
Date Opened:2008-08-18 11:16:25Date Closed:2011-06-07 14:02:39
Versions:Frequency of
Environment:Attachments:( 0) multi_answers.log.gz

Queue (ringall) -> Local channel -> Dial(SIP/device,M(answe_macro))

If two or more agents answer simultaneously, answer macro of Agent 1 starts excuting, then answer macro of Agent 2 starts executing and so on. One of those answer macros ends first, and this call is bridged. However logics of answer macros may include some important logic which should be executed only upon bridging.

So, there is no way how to know which agent has actually answered. Also CDR is marked ANSWERED for all agents answering at the same time.

Whenever first channel is answered, it should somehow block all other parallel channels (originating from the same queue entry) from executing answer macro, until result of first channel is known. If first channel is bridged, other threads should return DIALSTATUS=CANCEL. Otherwise if first channel sets MACRO_RESULT to something (indicating that it won't bridge the call), other threads should resume one by one executing their own answer macro's.


[18:21:37] <atis_work> imagine a perfect queue...
[18:22:07] <atis_work> ringall and local channels calling Dial() with M(answer_macro)
[18:22:35] <@seanbright> that is not how i typically imagine perfect queues
[18:22:49] <atis_work> :)
[18:22:51] <@seanbright> Q <-- perfect queue
[18:23:04] <atis_work> so, the problem arises when two agents answer simultenously
[18:23:32] <atis_work> guess what, answer macro of first agent starts executing, and then - bump, answer macro of second agent executes too..
[18:24:50] <atis_work> so, the result is, some logics in answer macro of second agent got executed, and both CDRs are marked answered
[18:28:19] <atis_work> putnopvut: so, you got any ideas about this before i should start proposing my solutions?
[18:32:21] <@putnopvut> atis_work: hold on just a sec...
[18:34:26] <@putnopvut> atis_work: I have a general idea of why that's happening. I'd be interested in hearing your proposal first, though.
[18:35:50] <atis_work> well, whenever second agent has answered it shouldn't be hanged up immediately, as first agent can choose not to accept call..
[18:36:30] <atis_work> so, i would propose to somehow lock all ringed channels and don't allow answer macro to execute until first one has completed
[18:36:54] <atis_work> but i have no idea how to do that, some channel datastore magic..
[18:37:23] <atis_work> probably this situation is valid only on multiprocessor machines..
[18:37:46] <atis_work> the threading is just too good :)
[18:39:59] <@putnopvut> atis_work: hmm, that's a possibility. I need to see when the CDR is actually marked as answered...is that done in the answer macro?
[18:40:31] <atis_work> putnopvut: no, it's local channel marking them Answered, as Dial completes with ANSWER
[18:40:40] <atis_work> hold on, i'll pastebin a log
[18:40:46] <@putnopvut> excellent
[18:46:18] <atis_work> http://www.pastebin.ca/1177573
[18:46:38] <atis_work> i had to trim of beginning, as it's too large. it starts with first agent answering
[18:47:11] <atis_work> p.s. don't pay attention to errors about non-existing functions, it's just because i tried my dialplan on non-patched asterisk
[18:47:16] <@putnopvut> atis_work: thanks. I'll take a look.
[18:53:58] <@putnopvut> atis_work: are you seeing the cdr's for both local channels being answered?
[18:54:10] <atis_work> putnopvut: yes
[18:54:28] <atis_work> putnopvut: the problem is not only in CDRs, but also answer macro's executing..
[18:54:57] <atis_work> for me they contain logics that affects agent's ratio etc..
[18:59:31] <@putnopvut> atis_work: yeah, the basic problem appears to be that app_dial doesn't seem to be set up to be used in a multithreaded scenario from within a single application.
[19:00:37] <atis_work> putnopvut: i suspected something like that
[19:00:45] <@putnopvut> Some sort of inter-thread communication (whether it's locking as you suggested, or a thread condition, or something else) is necessary so that app_dial can let other threads that are dialing know that they need to stop.
[19:02:32] <atis_work> putnopvut: well, stop is already realized, as app_queue can terminate dial, resulting in dialstatus=CANCEL
[19:03:06] <atis_work> however, in this situation stop wouldn't be best, as first agent can choose to not accept current call, in which case next answered agent should get it
[19:03:07] <@putnopvut> atis_work: right, but app_dial itself is the one that needs to be able to signal the other threads which are dialing. By the time control returns to app_queue, it's too late.
[19:06:35] <atis_work> sounds like it.. upon one channel is answered, app_dial locks "something" and upon success executes answer macro. if failed, it should check for continue or not..
Comments:By: Leif Madsen (lmadsen) 2008-08-27 12:28:11

*CLI> core show application dial

   M(x[^arg]) - Execute the Macro for the *called* channel before connecting
          to the calling channel. <snip>

I'm wondering if maybe the fix here is to have a new option:

   E(x[^arg]) - Execute the Macro exclusively for the *called* channel before
          connecting to the calling channel.

There is a MacroExclusive() application which maybe we could use which would only allow a single Macro() call to be executed.

However, this probably doesn't actually solve the real problem of not knowing the channel that actually answered teh call until after all of this is done executing.

By: Leif Madsen (lmadsen) 2008-12-05 11:46:21.000-0600

I wasn't exactly sure if this would be considered a bug or a feature request, but after talking with putnopvut on IRC, he concluded it appears to be a bug. I've set the status of this issue to Acknowledged.

By: Leif Madsen (lmadsen) 2009-03-02 17:53:17.000-0600

Assigned to dvossel to take a look to determine if he can do anything to move this forward. Thanks!

By: David Vossel (dvossel) 2009-03-12 18:14:00

In 1.4, a macro can't execute within Queue() app, so it has to execute it within the Dial() app.  Since the Queue() app has no control of the executed macro, it turns out to be an enormous task to achieve what you're asking, one that probably isn't acceptable to put into 1.4.  I don't believe this is a bug either.  What you have set up is working as expected, it would just be nice if there were an easy way to do what you're wanting.  There are a few options available though.  You could attempt to do use the MacroExclusive() app and use a global variable to determine whether or not the call was accepted.  If you were willing to update to 1.6, you could execute the macro within the Queue() app which provides more control.  Sorry there doesn't appear to be an easy solution.  Hopefully this helps.  I'm going to go ahead and close this issue, feel free to reopen it if you deem it necessary.  Due to the complexity involved, it might be worth bring this up on the asterisk-dev mailing list if you have further comments.