Hi Guys Problem: Async Event Gateway is not send...
# lucee
c
Hi Guys Problem: Async Event Gateway is not sending data to custom CFC’s OnIncomingMessage() method Details: I have created an Event Gateway in the Lucee Web Admin, using the Async type. I have added the AsynchronousEventsListener as the
Listener Component
and a Custom CFC path to the
CFC
field When I make the following call:
Copy code
SendGatewayMessage(“eventName”, data)
The data gets passed to the
AsynchronousEvents.cfc ->  AsynchronousEventsListener.cfc ~ OnIncomingMessage()
But the data never gets sent to my Custom CFC via the method
OnIncomingMessage()
Does anyone know why?
b
The last time I looked at the async example, it was completley non-functional
I think @zackster reworked it, but possibly for Lucee 6
The one that used to ship with Lucee, was basically a no-op. It looked like someone had taken a once-working example and stripped out a bunch of code to the point where it no longer did anything
Mind you, this was quite some time ago
Actually that ticket is still marked "new" so maybe nothing was fixed ever?
c
Cheers for the link. If I am being honest, I don’t really understand the point of this kind of event gateway. It seems to just send data from Component A to Component B to Component C. I could just send the data from Component A to Component C, by normal instantiation. I am doing an ACF -> Lucee migration, so they want me to keep the existing methodology.
b
Honestly, just use a CFThread
The async component is a big cfthread equivalent 🙂
Lucee's event gateways have no actual queuing mechanism like Adobe's does
They are much simpler
With Adobe, if you called
sendGatewayMessage()
100,000 times in a row, Adobe would queue up those events and then process them out of that queue using a preset number of threads (limited by wither you're on CF Enterprise or CF Standard 😆 )
But on Lucee, when you call sendGatewayMessage(), its imply fires off the sendMessage() method in a thread right then
There is no internal queuing of events or threadpools, unless you build all of that yourself into your CFC
So if there's a chunk of logic you want to run where the main thread doesn't wait for it, you may as well just write this code
Copy code
thread {
  myComponent.doSomething()
}
👍 1
I don't even understand all of the code in Lucee async gateway-- for instance, what on earth is this line doing? https://github.com/lucee/Lucee/blob/d92786a43709b637193d1d711141726e3c89b0b0/core/src/main/cfml/context/gateway/AsynchronousEvents.cfc#L24
c
Yes. I saw the cfthread inside the
AsynchronousEvents.cfc -> SendMessage
, but actually the cfthread start & end tag were commented out. It was like someone thought let’s make it async, because it is inside a component with the title AsynchronousEvents 🤣 and the decided against it. So, I am not sure the one in Lucee 5+, is actually Asynchronous? 😵‍💫
b
I don't even understand what the point of the
while(true)
loop is either in the
start
method. Honestly, I'm not sure anyone who touched this knows what they were doing, lol
😂 1
Lucee internally spawns the thread
👍 1
which is not the same as the worthless thread from the start function which just sits there for no apparent reason.
c
Yes. It’s almost like someone wrote this on Christmas Eve, 10 minutes before the holidays start. 🤩
When it says:
Copy code
getListener().onIncomingMessage(local.event);
Is that referring to:
Copy code
AsynchronousEventsListener.cfc -> onIncomingMessage()
Or:
Copy code
CustomCFC -> onIncomingMessage()
b
Actually, I take back the bit about the thread. Looking at the Lucee source code, the start and stop methods are in their own thread. The sendMessage() method does NOT appear to be. Which would mean the thread is actually necessary for the async gateway to be.... async. Which prolly means it was commented out at some point for testing
👍 1
I'm fairly sure you can use the asyncronoueventlistener or create your own, but I don't think there's actually any reason to use the baked in one
I honestly just think it's an example
The entire thing is example-quality 🙂
Yeah, that listener file bundled with Lucee is simply an example listener that does nothing but log the info
👍 1
you'd want to provide your own listener that actually did something with the message
But I'm 94% certain it's not currently actually async. You can test easily by putting a
sleep(10000)
in your listener and see if the
sendGatewayMessage()
blocks for 10 seconds or returns right away
c
But it adds that [example AsynchronousEventListener] automatically to the Listener Component field in the Web Admin Event Gateway -> Async form. And then there is another field which is for your own Custom CFC? Unfortunately the system never manages to connect to my Custom CFC 🤷‍♀️
b
Can you show a screenshot of what you mean?
Ahh yes, I'm pretty sure the CFC path isn't actually used
Just the listener
Like I said, this example was all sorts of cobbled together the last time I looked at it
I think someone had the original idea of • the gateway CFC • which calls the listener • which delegates to another CFC of your design but when you step back and think about it for a sec, you realize the third bullet is pretty pointless
c
MicrosoftTeams-image (11).png
b
The CFC path is basically never used-- at least not in the current implementation
Ignore it add add your custom CF as the listener
Then this code
Copy code
getListener().onIncomingMessage(local.event);
will actually call your code
👍 1
The form fields on that page are dynamic based on the config here
Copy code
core\src\main\java\resource\context\admin\gdriver\AsynchronousEvents.cfc
👍 1
c
Cheers for the explanation. I mean unless I spoke to you, I am not sure how I would have know this? I will give this a go...
I have added my Custom CFC Listener to both fields:
Copy code
/la_reporting/model/RunReport.cfc
Is a mapping path, by the way. It is one directory above the webroot, which is why I cannot use normal CFC path dot notation. And now I get:
Copy code
"INFO","XNIO-1 task-2","04/18/2023","21:28:27","lucee_context5.3.9.166","Event Gateway reportinggateway stopping"
"INFO","Thread-144","04/18/2023","21:28:27","lucee_context5.3.9.166","Event Gateway reportinggateway stopped"
"INFO","XNIO-1 task-2","04/18/2023","21:28:27","lucee_context5.3.9.166","Asyn CFC initialized path /la_reporting/model/RunReport.cfc"
"INFO","Thread-279","04/18/2023","21:28:28","lucee_context5.3.9.166","Event Gateway reportinggateway started"
"INFO","Thread-286","04/18/2023","21:28:31","lucee_context5.3.9.166","Event Gateway reportinggateway stopping"
"INFO","Thread-279","04/18/2023","21:28:31","lucee_context5.3.9.166","Event Gateway reportinggateway stopped"
"INFO","Thread-286","04/18/2023","21:28:31","lucee_context5.3.9.166","Event Gateway reportinggateway started"
"INFO","XNIO-1 task-9","04/18/2023","21:28:47","lucee_context5.3.9.166","sendMessage - Event Listener"
"INFO","XNIO-1 task-9","04/18/2023","21:28:47","lucee_context5.3.9.166","Event Gateway Component [lucee.extension.gateway.AsynchronousEvents] has no accessible Member with name [LISTENER]"
b
John on my phone now... What was the old listener value
It may need to be dot.path.to.component
c
OK. maybe you are saying I have to create two new files to replace both:
Copy code
\lucee-5.3.9.166\WEB-INF\lucee-web\components\lucee\extension\gateway\AsynchronousEventsListener.cfc

\lucee-5.3.9.166\WEB-INF\lucee-web\components\lucee\extension\gateway\AsynchronousEvents.cfc
So currently I have written a replacement for the listener, at:
Copy code
la\Reporting\model\RunReport.cfc
But now I need to create a 2nd custom CFc to replace:
Copy code
\lucee-5.3.9.166\WEB-INF\lucee-web\components\lucee\extension\gateway\AsynchronousEvents.cfc
Something like:
Copy code
la\Reporting\model\RunReportEvent.cfc
old listener value
Copy code
lucee.extension.gateway.AsynchronousEventsListener
OK. I have been playing around with multiple combinations and I cannot get it to work. The Web Admin seems to only play nicely with the example files. If you try and add your own events & listeners, it just says that it cannot find the file. I have tried putting stuff in the webroot. I have tried using CFC dot notation and absolute file paths, with no success. I suspect the Event Gateway module in Lucee 5+ is broken. I will just use a
cfthread
in situ.
b
@Charles Robertson I just tested and the async gateway works just like I said
firstly, it has an endless loop that chews your CPU
until you add a sleep into the while loop in the start method of this file
Copy code
C:\Users\Brad\.CommandBox\server\8A7BBDE95D7EC758F1D472B86AF89506-asyncgateway\lucee-5.3.10.120\WEB-INF\lucee-web\components\lucee\extension\gateway\AsynchronousEvents.cfc
The default listener does work though out of the box (despite the CPU-killing loop). Runnning
Copy code
sendGatewayMessage( 'test', { 'brad' : 'wood' } )
puts the following message
Copy code
"INFO","XNIO-1 task-5","04/18/2023","16:52:21","lucee_context5.3.10.120","CFMLAysncListener onIncomingMessage -Event Listener"
in the this log file
Copy code
C:\Users\Brad\.CommandBox\server\8A7BBDE95D7EC758F1D472B86AF89506-asyncgateway\lucee-5.3.10.120\WEB-INF\lucee-web\logs\AsynGateWay.log
I created a file in my web root called
listener.cfc
and created this config
Note, the CFC path DOES NOTHING AT ALL, but you have to put a valid file there just to make the stupid form save
The listener path is the dot-notation path using a mapping if necessary, but a serer-level mapping. An Application.cfc mapping won't work here.
I put this method in my listener
Copy code
public void function onIncomingMessage(struct CFEVENT={}){
		systemOutput( arguments, 1 )
	}
and running the same code as above put this in my console
Copy code
[INFO ] {"CFEVENT":{"DATA":{"brad":"wood"},"ORIGINATORID":"1BAB936D-2C2E-4965-9E145804DF9E931B","GATEWAYTYPE":"","HOSTNAME":"DESKTOP-IAN6MSO","CFCPATH":"","CFCMETHOD":"","TIMEOUT":"","METHOD":""}}
Also note, you must restart Lucee (which can be via the button in the server admin) to pick up any changes to the listener CFC
If you wanted to make async gateway that didn't suck, you'd need to create your own version of
Copy code
C:\Users\Brad\.CommandBox\server\8A7BBDE95D7EC758F1D472B86AF89506-asyncgateway\lucee-5.3.10.120\WEB-INF\lucee-web\components\lucee\extension\gateway\AsynchronousEvents.cfc
and
C:\Users\Brad\.CommandBox\server\8A7BBDE95D7EC758F1D472B86AF89506-asyncgateway\lucee-5.3.10.120\WEB-INF\lucee-server\context\context\admin\gdriver\AsynchronousEvents.cfc
which removed the superfluous CFC path and fixed the stupid while/true loop of doom
Those files also must go directly in the Lucee server home which makes shipping a custom event gateway type a total pain in the butt like no one ever thought through how that would work in an automated deploy.
The while loop can be entirely removed from the start method and the status simply set to
running
. I honestly have no clue what the purpose of that ever was for.
Confirmed, it's defo not async with the thread commented out
You can't simply uncomment the thread tag however, as the code doesn't pass
data
into a visible scope-- likekly why someone commented it out in the first place because they wouldn't get it working, lol
You'd need to do this in order for it to work and actually be async
Copy code
thread data=data{
                local.event ={
                    ...
                    Data = attributes.data,
                    ...
                };
                    log text="sendMessage - Event Listener HostName..." file=this.logfile;
                getListener().onIncomingMessage(local.event);

             }
👍 1
Which, even that isn't fantastic as the try catch won't capture errors in the actual listener.
Anyway, you get the picture- it all can be made to work. But the async gateway as it ships is pretty worthless, and I don't think it got much better in 6.0
👍 1
c
OK. I will have a look tomorrow. I just couldn’t get it to connect to my custom listener. But I think the example listener was being cached somewhere. I think I will make those changes to the two AsynchronousEvents.cfc files, because I don’t want to put unnecessary load onto the server.
OK. This is why nothing worked for me. I only did a server restart, not a Lucee restart. 🥴 I will try again tomorrow. Wait a second? I am using CommandBox. Surely a server restart is a Lucee restart? I used the restart function in the Lucee server tray icon? Surely this is the same thing?
OK. I feel something is being cached. I am getting this:
Copy code
"INFO","main","04/19/2023","11:07:59","lucee_context5.3.9.166","Asyn CFC initialized path /la_reporting/model/RunReport.cfc"
"INFO","main","04/19/2023","11:07:59","lucee_context5.3.9.166","Asyn CFC initialized path C:\domains\acf-lucee-shared\shared\la\CF-INF\cfcomponents\la\RefreshCandidateManagerCache.cfc"
"INFO","Thread-4","04/19/2023","11:07:59","lucee_context5.3.9.166","Event Gateway reportinggateway started"
"INFO","Thread-5","04/19/2023","11:07:59","lucee_context5.3.9.166","Event Gateway refreshcandidatemanagercache started"
"INFO","XNIO-1 task-7","04/19/2023","11:14:24","lucee_context5.3.9.166","sendMessage - Event Listener"
"INFO","XNIO-1 task-7","04/19/2023","11:14:24","lucee_context5.3.9.166","Event Gateway Component [lucee.extension.gateway.AsynchronousEvents] has no accessible Member with name [LISTENER]"
But there is no mention of
lucee.extension.gateway.AsynchronousEvents
in the:
Copy code
Web admin -> Event Gateway -> reportinggateway
I have stopped and started the server using the CommandBox tray icon
I think that:
Copy code
C:\Users\ADMCharlesr\.CommandBox\server\A39A87EE2EFB28FAFA02EAB99EA6149F-system_learningassistant_lucee\lucee-5.3.9.166\WEB-INF\lucee-web\components\lucee\extension\gateway\AsynchronousEvents.cfc
Is having problems, finding my listener:
Copy code
la\Reporting\model\RunReport.cfc
Now let me explain my custom listener's path:
Copy code
Listener Component = la_reporting.model.RunReport
la_reporting
is a server level mapping:
It may have something to do with the fact that my listener is one directory above the webroot:
Copy code
webroot = la\Code
But I have tested with a custom listener that is in the webroot, and it still cannot find it?
Even when I add the custom listener under the webroot, I still get:
Copy code
"INFO","XNIO-1 task-11","04/19/2023","12:17:25","lucee_context5.3.9.166","Event Gateway ERROR Component [lucee.extension.gateway.AsynchronousEvents] has no accessible Member with name [LISTENER]"
When I added a dump of the listener in the:
Copy code
C:\Users\ADMCharlesr\.CommandBox\server\A39A87EE2EFB28FAFA02EAB99EA6149F-system_learningassistant_lucee\lucee-5.3.9.166\WEB-INF\lucee-web\components\lucee\extension\gateway\AsynchronousEvents.cfc -> init()
It spits out the default listener rather than the custom listener?
I am using EHCache, so I wonder if that is affecting things?
I am also beginning to wonder whether the name of the listener must contain the word
Listener
, in it?
b
Yes, a server restart is a superset of a Lucee restart
The error about the listener variable not being defined is one I saw as well and it always went away when I restarted Lucee. I don't understand how the error happens, but I assume there is an error happening in the CFC's constructor.
Are you watching the specific log file for the gateway, it's full of information.
Also, did you remove this code
Copy code
writeDump(var="#arguments#", output="C:\Users\HP\Desktop\test.html", format ="classic");
that will error on your machine 🙂
👍 1
No, the word "listener" is not required.
👍 1
I really wasn't trying to talk you back into using the gateway-- cfthread is still the same thing-- I just wanted to be clear that the gateway does work with some adjustments.
I really have no idea what you've got going on without spending more time than I have right now to understand all the changes you've made and where.
All I know is I spun up a successful async event gateway last night on Lucee 5.3 with the steps I detailed
z
my ears are burning, um from recollection, if the gateway is under one of the system mappings aka /lucee, it's set to inspect once, hence the restart being required
👍 1
🙏 1
c
Thanks for all your help. I will keep investigating, I guess I will get it to work, one day. For now, I am just going to use a thread, instead of using
SendGatewayMessage()
, as Brad suggested...🙂
👍 1