[cisco-voip] UCCX Callback Script

Anthony Holloway avholloway+cisco-voip at gmail.com
Fri Nov 15 15:30:13 EST 2019


Bump.

On Thu, Nov 14, 2019 at 10:12 AM Anthony Holloway <
avholloway+cisco-voip at gmail.com> wrote:

> 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/20191115/a8fe8a0e/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/20191115/a8fe8a0e/attachment.png>


More information about the cisco-voip mailing list