[cisco-voip] UCCX Callback Script

Anthony Holloway avholloway+cisco-voip at gmail.com
Thu Nov 14 11:12:32 EST 2019


Tanner, I ran a test and actually, anything inside the Do step will block
events.

As a test, I used this Do step:

Do {
    int i = 0;
    do {
        i++;
    } while (i <= 100000000);
}

And then hang up the a call during the do step, and see that nothing
happens; no interrupt.  However, the label we ask the script to goto on CIE
is then the label which is executed next.  This seems obvious when you
consider that there isn't a toggle-able option for interrupt handling on
the Do step.

But back to your method of handling callbacks, because I find it so
interesting.

I found that if in script 2, if the Agent just hangs up, you cannot
re-queue the call, because CL2 is now dead.  And in order to generate a new
active Contact Leg, you'd need to re-do the place call step, which means
you would need to signal something back to script 1.

Signaling between two running scripts is non-trivial and requires polling,
since Cisco hasn't implemented promises yet.  ;)

On Mon, Nov 11, 2019 at 2:13 PM Anthony Holloway <
avholloway+cisco-voip at gmail.com> wrote:

> Tanner, That was tongue in cheek my man.  I was really looking forward to
> having more of a conversation with you about the thread locking solution,
> and balancing the pros and the cons with it.
>
> Also, I'm still confused how you are doing your solution, pertaining
> specifically to keeping script 1 alive, as I have found that it needs to
> remain alive, else you lose Leg 1's Contact (likely due to it being Garbage
> Collected).
>
>
>
> On Fri, Nov 8, 2019 at 11:43 AM Anthony Holloway <
> avholloway+cisco-voip at gmail.com> wrote:
>
>> [image: image.png]
>>
>> On Wed, Nov 6, 2019 at 6:18 PM Anthony Holloway <
>> avholloway+cisco-voip at gmail.com> wrote:
>>
>>> To your last point about CIE: it doesn't work for me anyway, and I'm not
>>> trying to have the script do anything else, so threadlocking doesn't sound
>>> all that bad.  Unless of course you're trying to tell me that it's not just
>>> the thread my script is running within, but the entire CCX Engine as a
>>> thread, then yeah, that's pretty terrible.  Though, I just did a test,
>>> where I thread slept for 100 seconds in script A, and during that time,
>>> called into script B, and made sure everything worked fine while the
>>> threadlocking should have been taking place.  So, I would say it's not the
>>> CCX Engine as a whole, and likely each script is executed in its own
>>> thread.  This should be acceptable in this one use case.
>>>
>>> It's still a mystery to me how you're handling script 1.
>>>
>>> It kind of sounds like you are doing a 999s delay loop, but are you
>>> checking for the contact to be active still with the Get Contact Info
>>> step?  So, essentially the same thing I was doing, but with script steps
>>> instead (and less frequently)?  If so, then your script 1 stays active for
>>> ~15 minutes, worst case scenario, after the callback has been completed,
>>> correct?
>>>
>>> E.g.,
>>>
>>> CL1 = Place Call ()
>>>     Successful
>>>         LABEL0:
>>>         Delay 999s
>>>         is_active = Get Contact Info (CL1)
>>>         If (is_active)
>>>             True
>>>                 Goto LABEL0
>>> End
>>>
>>> On Wed, Nov 6, 2019 at 5:55 PM Tanner Ezell <tanner.ezell at gmail.com>
>>> wrote:
>>>
>>>> I place an exception handler for contact inactive, checking for the
>>>> callback contact via get Contact Info step to make sure the caller hanging
>>>> up didn't catch the exception.
>>>>
>>>> From there I have programmed in resiliency for the callback to be hung
>>>> up by the agent, but beyond that there is a Delay 999s loop. You'll never
>>>> hit the limit as you've discovered.
>>>>
>>>> Would not recommend Thread.sleep inside your code as it will thread
>>>> lock the task and may interfere; for example, it may prevent the CIE to be
>>>> caught properly in that script. Use Delay step, it's thread safe and is
>>>> built in a way that allows exceptions to be handled.
>>>>
>>>> On Wed, Nov 6, 2019 at 4:46 PM Anthony Holloway <
>>>> avholloway+cisco-voip at gmail.com> wrote:
>>>>
>>>>> Ok, so I solved the looping thing by...well...looping.  :/
>>>>>
>>>>> So, loops themselves are not the problem, rather it's the finite
>>>>> script steps we can execute which are the problem...err...challenge.
>>>>>
>>>>> Since the CIE doesn't get thrown in script 1 properly (bug?), I used a
>>>>> Do step in the success branch of the Place Call step to wait for the active
>>>>> state of CL1 to change.  Like so:
>>>>>
>>>>> Do {
>>>>>     do {
>>>>>         java.lang.Thread.sleep(1000);
>>>>>     } while (contact_leg_1.isActive());
>>>>> }
>>>>>
>>>>> CL1 only becomes inactive once the Agent acknowledges the callback and
>>>>> the call redirect is successful.  Therefore, I get all the benefits of
>>>>> Tanner's solution, plus I can keep the max steps at 1,000, and technically
>>>>> queue for 12 hours (the CallManager default max call timer).
>>>>>
>>>>> I think this should work just fine, though, more rigorous testing will
>>>>> be needed.  What do you think?
>>>>>
>>>>> On Wed, Nov 6, 2019 at 5:10 PM Anthony Holloway <
>>>>> avholloway+cisco-voip at gmail.com> wrote:
>>>>>
>>>>>> I see that the contact in both scripts is actually the same contact,
>>>>>> but each script views the contact from a different leg/sequence number
>>>>>> (I.e., Outbound leg versus Inbound leg)
>>>>>>
>>>>>> *Contact Created with Place Call Step (AKA CL1 for Call Leg 1)*
>>>>>>
>>>>>> §com.cisco.wf.subsystems.jtapi.CallImpl§JTAPICallContact[id=155,
>>>>>> implId=633001/1,state=STATE_ANSWERED_IDX,inbound=false,App
>>>>>> name=App1,task=26000000240,session=3000000115,seq num=0
>>>>>> ,cn=2411,dn=null,cgn=2402,ani=null,dnis=null,clid=null,atype=OUTBOUND
>>>>>> ,lrd=null,ocn=2411,route=RP[num=0000],OrigProtocolCallRef=null,DestProtocolCallRef=000000000009A8A902F728A200000000,TP=2402]§
>>>>>>
>>>>>>
>>>>>> *--Triggering Contact-- in the Queuing Script (AKA CL2 for Call Leg
>>>>>> 2)*
>>>>>>
>>>>>> §com.cisco.wf.subsystems.jtapi.CallImpl§JTAPICallContact[id=156,
>>>>>> implId=633001/1,state=STATE_ANSWERED_IDX,inbound=true,App
>>>>>> name=App2,task=26000000241,session=3000000115,seq num=1
>>>>>> ,cn=2411,dn=2411,cgn=2402,ani=null,dnis=null,clid=null,atype=DIRECT
>>>>>> ,lrd=null,ocn=2411,route=RP[num=2411],OrigProtocolCallRef=000000000009A8A902F728A400000000,DestProtocolCallRef=null,TP=2401]§
>>>>>>
>>>>>>
>>>>>> So, things like Set/Get Enterprise Call Info work on the same
>>>>>> contact, because they are leg independent, whereas things requiring media,
>>>>>> like Play Prompt, are call leg dependent, and need to reference the correct
>>>>>> call leg of the contact.  Hence, you have to pass the CL1 object into
>>>>>> Script 2, in order to interact with the Agent from CL1.
>>>>>>
>>>>>> Unfortunately, if script 1 ends, there seems to be some clean up
>>>>>> tasks which run at the end of script 1 to unload CL1 from memory, and I am
>>>>>> getting an abort event in script 2, when trying to reference CL1.  As is
>>>>>> the case when I try to play media to the Agent or Call Redirect them to the
>>>>>> callback number.  If prevent script 1 from ending, and thus cleaning up
>>>>>> after itself, CL1 stays alive and script 2 works great.  The question for
>>>>>> me now is, how do I release script 1, without also releasing CL1?
>>>>>>
>>>>>> One thought I had was to setup a Contact Inactive listener in script
>>>>>> 1, and use the Delay step in script 1 for an absurd amount of time, like 12
>>>>>> hours, and then rely on the fact that once CL1 transfers the Agent to the
>>>>>> callback number, CL1 goes inactive, and thus the 12 hour delay is
>>>>>> interrupted and script 1 can now end.  In theory that is.  In practice,
>>>>>> script 1 never receives a CIE event, and the delay continues for the 12
>>>>>> hours.  No Beuno.
>>>>>>
>>>>>> Second thought was to signal something from script 2 to script 1, but
>>>>>> that requires looping in script 1 (polling).  No beuno.
>>>>>>
>>>>>> Which by the way, I should mention, I am looking at your solution as
>>>>>> a way to avoid looping, though you didn't specifically say that you have
>>>>>> figured out a way to avoid looping.  I was just being hopeful that somehow
>>>>>> your method did avoid looping.
>>>>>>
>>>>>> Like Brian Meade already mentioned, we have solved the "only once an
>>>>>> Agent answers" dilemma by using polling in script 1, and setting a flag in
>>>>>> script 2 once the agent answers, using Enterprise variables.  Polling
>>>>>> solves the Agent only hearing the message from the top, versus in the
>>>>>> middle, but it doesn't solve the finite script steps issue.
>>>>>>
>>>>>> Therefore, I am wondering how you are handling script 1, post
>>>>>> successful place call.
>>>>>>
>>>>>> Don't get me wrong, I'm still #TeamTanner, and will be converting my
>>>>>> callback method to yours, since there are some advantages.  I just have to
>>>>>> solve the script 1 clean up problem first.
>>>>>>
>>>>>> On Wed, Nov 6, 2019 at 4:09 PM Anthony Holloway <
>>>>>> avholloway+cisco-voip at gmail.com> wrote:
>>>>>>
>>>>>>> I actually got that part to work.  What I'm wondering about is what
>>>>>>> you are doing in script 1 (place call script) after the successful branch.
>>>>>>> Like, are you looping, are you delaying, are just ending?
>>>>>>>
>>>>>>> On Wed, Nov 6, 2019 at 3:52 PM Tanner Ezell <tanner.ezell at gmail.com>
>>>>>>> wrote:
>>>>>>>
>>>>>>>> It's really not all that complicated. Think of it this way, the
>>>>>>>> place call is the contact the agent is exposed to when they answer the
>>>>>>>> queued call, which of course is just the IVR.
>>>>>>>>
>>>>>>>> Pass the generated contact to the agent script (the one that has
>>>>>>>> the select resource), under the connected branch is when you know that your
>>>>>>>> other IVR application contact (from place call), connected to the agent.
>>>>>>>> Use the passed contact and play media just like you would any other
>>>>>>>> contact. In essence, you take the agent menu out of script 1 and put it in
>>>>>>>> script 2 :)
>>>>>>>>
>>>>>>>> With all that you can do some cool stuff, like ensuring the agent
>>>>>>>> doesn't just hang up (aka callback resiliency) and what to do if they do
>>>>>>>> (like re-queue, email a supervisor, re-call the agent, etc), can control if
>>>>>>>> the designated callback destination doesn't answer and some other fun stuff.
>>>>>>>>
>>>>>>>> happy hacking!
>>>>>>>>
>>>>>>>> On Wed, Nov 6, 2019 at 2:20 PM Anthony Holloway <
>>>>>>>> avholloway+cisco-voip at gmail.com> wrote:
>>>>>>>>
>>>>>>>>> Tanner, Can you describe, or show what you're doing in script 1,
>>>>>>>>> which has the Place Call step, inside the Successful branch?
>>>>>>>>>
>>>>>>>>> On Tue, Nov 5, 2019 at 4:30 PM Tanner Ezell <
>>>>>>>>> tanner.ezell at gmail.com> wrote:
>>>>>>>>>
>>>>>>>>>> Pssshhht....I'll share a "secret" for playing the agent menu only
>>>>>>>>>> when the agent answers..
>>>>>>>>>>
>>>>>>>>>> Pass the contact to the agent script, then play your agent menu
>>>>>>>>>> after they connect.
>>>>>>>>>>
>>>>>>>>>> Ez pz.
>>>>>>>>>>
>>>>>>>>>> Regards,
>>>>>>>>>> Tanner Ezell
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Tue, Nov 5, 2019 at 2:54 PM Brian Meade <bmeade90 at vt.edu>
>>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>>> Anthony,
>>>>>>>>>>>
>>>>>>>>>>> I'm curious how you handle catching when the agent answers the
>>>>>>>>>>> callback request.
>>>>>>>>>>>
>>>>>>>>>>> I've got my scripts checking to see if the CallBack contact was
>>>>>>>>>>> answered by setting some Enterprise Info in my callback queue script but I
>>>>>>>>>>> still have to check every few seconds to see if that Enterprise Info is set.
>>>>>>>>>>>
>>>>>>>>>>> I just max out the max steps to account for that.
>>>>>>>>>>>
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Brian Meade
>>>>>>>>>>>
>>>>>>>>>>> On Tue, Nov 5, 2019 at 4:19 PM Anthony Holloway <
>>>>>>>>>>> avholloway+cisco-voip at gmail.com> wrote:
>>>>>>>>>>>
>>>>>>>>>>>> Hi Tim,
>>>>>>>>>>>>
>>>>>>>>>>>> I think the idea of a flawless script is in the eyes of the
>>>>>>>>>>>> beholder.
>>>>>>>>>>>>
>>>>>>>>>>>> I don't personally use the example script from the repo; are
>>>>>>>>>>>> you talking about the one here:
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> script_respository_902\script_respository\release3\BaseLineAdvQueuing\BaseLineAdvQueuing.aef
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> If so, there a few things wrong with that script.
>>>>>>>>>>>>
>>>>>>>>>>>> For example, you said "...despite having Contact Inactive
>>>>>>>>>>>> exception error handling..."
>>>>>>>>>>>>
>>>>>>>>>>>> Yeah, they setup an exception handler at the top for
>>>>>>>>>>>> ContactInactiveException, but then they never clear it, or reset it, and so
>>>>>>>>>>>> if and when the caller disconnects while recording their message or
>>>>>>>>>>>> listening to the "success" prompt, the whole thing falls a part and fails,
>>>>>>>>>>>> sending script execution down to the ExceptionCIE label.
>>>>>>>>>>>>
>>>>>>>>>>>> Another thing wrong with it is that the waiting mechanism for
>>>>>>>>>>>> the Agent is such that it plays a relatively short prompt, waits 3 seconds
>>>>>>>>>>>> for input from the Agent, then repeats.
>>>>>>>>>>>>
>>>>>>>>>>>> If you consider every application has a max 1,000 steps it can
>>>>>>>>>>>> execute, and you subtract off the overhead of just getting the call to this
>>>>>>>>>>>> point (say 21 steps in the most streamlined of scenarios), that leaves you
>>>>>>>>>>>> with 32 minutes to queue a call, otherwise the call will be aborted.  Since
>>>>>>>>>>>> most people are only interested in callback when they have queue hold time
>>>>>>>>>>>> problems, this is likely to cause more issues than it solves.
>>>>>>>>>>>>
>>>>>>>>>>>> "...I’ve read that the Call Control Group and Dialog Group
>>>>>>>>>>>> should be different from the trigger on the originating application..."
>>>>>>>>>>>>
>>>>>>>>>>>> Can you link the source?
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> On Tue, Nov 5, 2019 at 10:59 AM Johnson, Tim <
>>>>>>>>>>>> johns10t at cmich.edu> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>>> Anyone have a callback script that is working flawlessly? We
>>>>>>>>>>>>> have implemented the solution in Cisco’s Advanced Queueing script and it’s
>>>>>>>>>>>>> seems to be working, but I’m seeing Contact Inactive Exceptions and Contact
>>>>>>>>>>>>> Creation errors in syslog each time the callback is used, despite having
>>>>>>>>>>>>> Contact Inactive exception error handling.
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> It seems that the issue may be related to the Place Call step
>>>>>>>>>>>>> which calls the trigger of the callback application. I’ve read that the
>>>>>>>>>>>>> Call Control Group and Dialog Group should be different from the trigger on
>>>>>>>>>>>>> the originating application (which is what we have setup), but I’m curious
>>>>>>>>>>>>> if those should also be different from what’s used on the callback
>>>>>>>>>>>>> application. If so, can I use the same CCG and DG from the original
>>>>>>>>>>>>> trigger, on the callback trigger?
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> For example, I have the following setup:
>>>>>>>>>>>>>
>>>>>>>>>>>>> App_A application has a trigger that uses CCG #8 and Dialog
>>>>>>>>>>>>> Group #0. In its script, it uses the Place Call step with CCG #25 and
>>>>>>>>>>>>> Dialog Group #3. This places the call to App_Callback application which has
>>>>>>>>>>>>> a trigger that uses CCG #25 and Dialog Group #3.
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> Tim Johnson
>>>>>>>>>>>>>
>>>>>>>>>>>>> Voice & Video Engineer
>>>>>>>>>>>>>
>>>>>>>>>>>>> Central Michigan University
>>>>>>>>>>>>>
>>>>>>>>>>>>> Phone: +19897744406 at cmich.edu
>>>>>>>>>>>>>
>>>>>>>>>>>>> Fax: +19897795900
>>>>>>>>>>>>>
>>>>>>>>>>>>> [image: webexemailsig] <https://cmich.webex.com/meet/johns10t>
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> _______________________________________________
>>>>>>>>>>>>> cisco-voip mailing list
>>>>>>>>>>>>> cisco-voip at puck.nether.net
>>>>>>>>>>>>> https://puck.nether.net/mailman/listinfo/cisco-voip
>>>>>>>>>>>>>
>>>>>>>>>>>> _______________________________________________
>>>>>>>>>>>> cisco-voip mailing list
>>>>>>>>>>>> cisco-voip at puck.nether.net
>>>>>>>>>>>> https://puck.nether.net/mailman/listinfo/cisco-voip
>>>>>>>>>>>>
>>>>>>>>>>> _______________________________________________
>>>>>>>>>>> cisco-voip mailing list
>>>>>>>>>>> cisco-voip at puck.nether.net
>>>>>>>>>>> https://puck.nether.net/mailman/listinfo/cisco-voip
>>>>>>>>>>>
>>>>>>>>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://puck.nether.net/pipermail/cisco-voip/attachments/20191114/b1c48788/attachment.htm>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: image.png
Type: image/png
Size: 62204 bytes
Desc: not available
URL: <https://puck.nether.net/pipermail/cisco-voip/attachments/20191114/b1c48788/attachment.png>


More information about the cisco-voip mailing list