ChannelListners infinitly growing - jxbrowser

In my JxBrowser Application I create and dispose a browser for each request based on given needs. After several hundred requests, I begin to received a "Failed to get Browser browserChannel" exception. In an attempt to debug this, I noticed that I have an ever growing number of ChannelListeners. I added the following code to my application after the browser.dispose() to see this.
if (CollectionUtils.isNotEmpty(IPC.getDefault().getMainChannel().getChannelListeners())) {
List<ChannelListener> channelListeners = IPC.getDefault().getMainChannel().getChannelListeners();
for(ChannelListener listener : channelListeners) {
logger.info("Listener: " + listener.getClass());
}
}
I see these 4 repeat in my logs as a result
2018-06-21 13:30:28,105 [pool-3-thread-1] INFO c.t.l.l.a.service.BrowserManager - Listener: class com.teamdev.jxbrowser.chromium.ZoomService$a
2018-06-21 13:30:28,105 [pool-3-thread-1] INFO c.t.l.l.a.service.BrowserManager - Listener: class com.teamdev.jxbrowser.chromium.NetworkService$a
2018-06-21 13:30:28,105 [pool-3-thread-1] INFO c.t.l.l.a.service.BrowserManager - Listner: class com.teamdev.jxbrowser.chromium.NotificationService$a
2018-06-21 13:30:28,105 [pool-3-thread-1] INFO c.t.l.l.a.service.BrowserManager - Listener: class com.teamdev.jxbrowser.chromium.ProtocolService$a
Is this there something I'm not disposing correctly? Is this a JxBrowser issue, maybe related to my IPCException?

These 4 listeners belong to the default IPC instance that is implemented as a singleton. So, once you access the default IPC instance through the IPC.getDefault(), these 4 listeners are registered and we never unregister them.
FYI: the library might create a lot of ChannelListeners inside. These listeners are part of the internal private logic. They are removed when it's necessary.
As for the "Failed to get Browser browserChannel" error message – this error message indicates that the library failed to initialize the Browser instance. In this case the log messages should be analyzed to detect the root cause of the issue.

Related

Consumer Error Handling in Symfony Messenger / RabbitMQ

I'm using the new Symfony Messenger Component 4.1 and RabbitMQ 3.6.10-1 to queue and asynchronously send email and SMS notifications from my Symfony 4.1 web application. My Messenger configuration (messenger.yaml) looks like this:
framework:
messenger:
transports:
amqp: '%env(MESSENGER_TRANSPORT_DSN_NOTIFICATIONS)%'
routing:
'App\NotificationBundle\Entity\NotificationQueueEntry': amqp
When a new notification is to be sent, I queue it like this:
use Symfony\Component\Messenger\MessageBusInterface;
// ...
$notificationQueueEntry = new NotificationQueueEntry();
// [Set notification details such as recipients, subject, and message]
$this->messageBus->dispatch($notificationQueueEntry);
Then I start the consumer like this on the command line:
$ bin/console messenger:consume-messages
I have implemented a SendNotificationHandler service where the actual delivery happens. The service configuration:
App\NotificationBundle\MessageHandler\SendNotificationHandler:
arguments:
- '#App\NotificationBundle\Service\NotificationQueueService'
tags: [ messenger.message_handler ]
And the class:
class SendNotificationHandler
{
public function __invoke(NotificationQueueEntry $entry): void
{
$this->notificationQueueService->sendNotification($entry);
}
}
Until this point, everything works smoothly and the notifications get delivered.
Now my question: It may happen that an email or SMS cannot be delivered due to a (temporary) network failure. In such a case, I would like my system to retry the delivery after a specified amount of time, up to a specified maximum number of retries. What is the way to go to achieve this?
I have read about Dead Letter Exchanges, however, I could not find any documentation or example on how to integrate this with the Symfony Messenger Component.
What you need to do is tell RabbitMQ, that the message is rejected instead of acknowledged. By default the messenger will take care of this inside the AmqpReceiver. As you can see there, if you throw an exception that implements the RejectMessageExceptionInterface inside your handler, the message will automatically be rejected for you.
You could also "simulate" this behaviour with custom middleware. I created something like it, in a small demo application. The mechanism consists of a middleware that wraps the (serialized) original message inside a new RetryMessage and sends it via a custom message bus to a different queue, used as a dead letter exchange. The handler for that message will then unpack the RetryMessage (getting the original message and deserializing it) and transmit it over the default bus:
See:
RetryMessage
RetryMiddleware
messenger.yaml
RetryMessageHandler
This is a basic setup which rejects the message and allows you to consume it again instantly(!). You probably want to add additional information such as headers for timestamps when delaying the consumption to improve on this. For this you should look at writing your own receiver, middleware and/or handler.

Get detailed error for exception in SignalR Core Hub method execution

When I call Hub method I get frame response:
{"invocationId":"1","type":3,"error":"An error occurred while updating
the entries. See the inner exception for details."}
How can I get detailed error report (row and file where error occurred) without manually debugging and using step over and check where the code raise exception.
On net I found plenty codes where EnableDetailedErrors is used
services.AddSignalR(options =>
{
options.Hubs.EnableDetailedErrors = true;
});
but options (at least in version 1.0.0-alpha2-final) does not have property Hubs.
This is what you need to do in core (not sure the exact version this was added):
// signalR
services.AddSignalR(options =>
{
if (Environment.IsDevelopment()) {
options.EnableDetailedErrors = true;
}
});
It goes without saying that the reason this is disabled by default in production is for security reasons. So be careful not to expose things you may not wish 'hackers' to see in any of the exceptions you may throw.
Implementing the above setting will reveal a more detailed message in the browser console, whcih you can also see in the websocket debugging tab:
Quick tip:
I've set up SignalR twice now on ASPNetCore and I think I've made the same mistake both times:
// from typescript client arguments are passed like this
this.hubConnection.invoke('SendMessage', 'simon', 'hello');
// not like this
this.hubConnection.invoke('SendMessage', ['simon', 'hello']);
Also invoke will wait for a response, while send does not. So you may not see errors using send.
Currently the option to enable detailed errors is not implemented. There is an issue tracking this. My recommendation would be to turn on logging on the server side - the original exception will be logged there.

turn off AKKA IO-TCP logging

I want to turn off the logging of the following (lifecycle?) events, which configuration directive controls this?
DEBUG [akka://MyActorSystem/system/IO-TCP/selectors/$a/371] - started (akka.io.TcpOutgoingConnection#558309d8)
DEBUG [akka://MyActorSystem/system/IO-TCP/selectors/$a/371] - now watched by Actor[akka://MyActorSystem/system/IO-TCP/selectors/$a#
DEBUG [akka://MyActorSystem/system/IO-TCP/selectors/$a/371] - Attemptingconnection to [localhost/127.0.0.1:12002]
DEBUG [akka://MyActorSystem/system/IO-TCP/selectors/$a/371] - Connection established to [localhost/127.0.0.1:12002]
DEBUG [akka://MyActorSystem/system/IO-TCP/selectors/$a/371] - stopped
You can disable the lifecycle log messages ("started", "watched", "stopped") with the following setting in application.conf:
akka {
actor {
debug {
# disable DEBUG logging of actor lifecycle changes
lifecycle = off
}
}
}
If you're using remoting:
akka {
remote {
log-remote-lifecycle-events = off
}
}
The TCP connection log messages in your excerpt (which are set here and here) are hard-coded at the debug level and, unlike the lifecycle events, cannot be disabled. To prevent the logging of these messages, set your global logging level to a level that is more coarse-grained than debug (doing this also prevents the logging of lifecycle events, regardless of the above settings). More information on logging is found in the official documentation.

Slick2D KryoNet Applet

I'm using Kryonet with Slick2d to make a java game.
It works fine when running as a java application, however when running as an applet I get the following error:
00:00 INFO: [kryonet] Server opened.
00:04 DEBUG: [kryonet] Port 9991/TCP connected to: /(ip):55801
00:04 DEBUG: [kryo] Write: RegisterTCP
00:04 INFO: [kryonet] Connection 1 connected: /(ip)
00:04 INFO: [SERVER] Someone has connected.
00:04 ERROR: [kryonet] Error reading TCP from connection: Connection 1
com.esotericsoftware.kryonet.KryoNetException: Error during deserialization.
at com.esotericsoftware.kryonet.TcpConnection.readObject(TcpConnection.java:141)
at com.esotericsoftware.kryonet.Server.update(Server.java:192)
at com.esotericsoftware.kryonet.Server.run(Server.java:350)
at java.lang.Thread.run(Unknown Source)
Caused by: com.esotericsoftware.kryo.KryoException: Buffer underflow.
at com.esotericsoftware.kryo.io.Input.require(Input.java:162)
at com.esotericsoftware.kryo.io.Input.readLong(Input.java:621)
at com.esotericsoftware.kryo.io.Input.readDouble(Input.java:745)
at com.esotericsoftware.kryo.serializers.DefaultSerializers$DoubleSerializer.read(DefaultSerializers.java:141)
at com.esotericsoftware.kryo.serializers.DefaultSerializers$DoubleSerializer.read(DefaultSerializers.java:131)
at com.esotericsoftware.kryo.Kryo.readClassAndObject(Kryo.java:735)
at com.esotericsoftware.kryonet.KryoSerialization.read(KryoSerialization.java:57)
at com.esotericsoftware.kryonet.TcpConnection.readObject(TcpConnection.java:139)
... 3 more
00:04 INFO: [SERVER] Someone has disconnected.
00:04 INFO: [kryonet] Connection 1 disconnected.
The server is running locally as a runnable jar and the client applet in a HTML file locally aswell, which is running xampp to act as a web server.
I've tried different serializers, buffer sizes and sending just single String/Booleans etc, it just doesn't seem to like anything.
The client connects to the server perfectly fine, however when it comes to sending any packets, I get the above error, no matter what packet is sent.
Any help/advice would be really appreciated - I've been stumped on this for a while!
Thanks
I believe I have the same problem or at least similar one. I am using Kryonet for server and client. The client is an applet and when I run it trough Eclipse's Applet Viewer it works fine. When I run it trough a web server I get similar errors. Client and server connect, server receives client's packets, but the client gives an error wherever it tries any deserialization. I found that the applet permissions are to blame. If you change the permissions of the Applet Viewer (if you are using Eclipse) to be the same as of a web page, you will get the same errors. The advantage is that you can then debug the problem.
To change the permissions for Eclipse:
Go to your project folder \bin\ and open "java.policy.applet". Inside you should have:
grant {
permission java.security.AllPermission;
};
Change that to:
grant {
permission java.io.FilePermission "<<ALL FILES>>", "read, write, execute, delete";
permission java.net.SocketPermission "*", "accept, connect, listen, resolve";
permission java.util.PropertyPermission "*", "read, write";
permission java.lang.RuntimePermission "*";
permission java.awt.AWTPermission "showWindowWithoutWarningBanner";
};
With this change I had the same behavior for Applet Viewer as with an embedded applet. This is not a full solution, but can help in finding the cause of the problem.
Update:
I have found what is the problem in my case. The problem is in the FieldSerializer and the other serializers using it. When a class is registered, the FieldSerializer goes over it's fields and set's them all to be accessible. This operation is not allowed for an applet. The result is wrong registration and serialization/deserialization. I have found 2 workarounds:
1) Use of another serializer. The default one is a FieldSerializer and can be changed using
public void setDefaultSerializer (Class<? extends Serializer> serializer)
another option is to set the serializer when registering each class. Do not use serializers based on the FieldSerializer.
2) Try to fix the FieldSerializer. What I am doing is not fully correct, but it works in my case. We will make the FieldSerializer continue the registration if setting of the accessibility is causing an Exception. Another thing we need to do is set all fields of the classes we register to public. TO change the FieldSerializer you need the Kryo sources. Go to FieldSerializer.java, mething rebuildCachedFields(). You will find the following code there:
if (!field.isAccessible()) {
if (!setFieldsAsAccessible) continue;
try {
field.setAccessible(true);
} catch (AccessControlException ex) {
continue;
}
}
You need to change that to:
if (!field.isAccessible()) {
if (setFieldsAsAccessible)
try {
field.setAccessible(true);
} catch (AccessControlException ex) {
}
}
The other thing that needs to be changed is all of the registered classes to have only public fields.
I have similar problem in gradle build. May be you need just increase memory (either heap or PermSize) for the applet JVM

Blazor Server - the circuit failed to initialize

I have published the BlazorApp1 app created by the VS2019 Blazor template to a production server. Since it is a sub-site, I made 3 changes:
in _Host.cshtml replaced the base tag with <base href="/BlazorApp1/" >
in Startup.cs added app.UsePathBase("/BlazorApp1")
in web.config, changed the hostingModel to outofprocess and stdoutLogEnabled to true
When navigating to the site I almost always get the following error:
Unhandled Exception Page must be reloaded
This is displayed in the browser console: (replaced my site with contoso)
[2020-06-02T18:39:49.445Z] Information: Normalizing '_blazor' to 'http://www.contoso.com/BlazorApp1/_blazor'. blazor.server.js:1:5212
[2020-06-02T18:39:49.936Z] Information: WebSocket connected to ws://www.contoso.com/BlazorApp1/_blazor?id=5yq6pI_jo1ByPZtskEjjmw. blazor.server.js:1:5212
[2020-06-02T18:39:50.132Z] Error: The circuit failed to initialize. blazor.server.js:15:27309
log http://www.contoso.com/BlazorApp1/_framework/blazor.server.js:15
C http://www.contoso.com/BlazorApp1/_framework/blazor.server.js:8
S http://www.contoso.com/BlazorApp1/_framework/blazor.server.js:8
invokeClientMethod http://www.contoso.com/BlazorApp1/_framework/blazor.server.js:1
invokeClientMethod .../BlazorApp1/_framework/blazor.server.js:1
processIncomingData .../BlazorApp1/_framework/blazor.server.js:1
onreceive .../BlazorApp1/_framework/blazor.server.js:1
onmessage .../BlazorApp1/_framework/blazor.server.js:1
[2020-06-02T18:39:50.141Z] Information: Connection disconnected. blazor.server.js:1:5212
Error: Invocation canceled due to the underlying connection being closed. blazor.server.js:1:20001
I can't find any other clues about what's happening. There are no exceptions shown in the log.
The problem was resolved by using only lowercase characters in the <base> tag:
<base href="/blazorapp1/" >
It has just happened to me as well, but I had the base tag specified correctly. This error can also occur in a rare case when you have ambiguous constructors defined for one of your dependency injected services if both match all the parameters (possibly by accident due to inheritance). The verbose log won't point to that issue. Be aware that purposeful creation of multiple constructors for dependency injected services is considered an anti-pattern.
For me it happened because I put an async call inside a constructor of a class in DI, so, yeah, that's a stupid error which can mean anything.

Resources