[cisco-voip] UCCX Callback Script

Anthony Holloway avholloway+cisco-voip at gmail.com
Wed Nov 6 19:18:51 EST 2019


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/20191106/b0fee4c8/attachment.htm>


More information about the cisco-voip mailing list