After some further debugging I was able to workaround the
described problem by making the connection to the virtual
machine work regardless of the used hostname in the endpoint
description.
I used some constant value for ENDPOINT_ID and used
RemoteConstants.ENDPOINT_CONNECTTARGET_ID to define the "real
network" target/host to connect to:
props.put(RemoteConstants.ENDPOINT_CONNECTTARGET_ID,
"ecftcp://" + host + ":8889/server");
props.put(ENDPOINT_ID, "p4://server");
So no more hostname matching to identify the correct service on
the target machine.
Hi Scott,
thanks for your suggestion, but the described fix does not
seem to work. The returned container is always null and so
cannot be disconnected. This is caused by the importEndpoint
of the importReference being null.
This is what I'm doing:
1) register my remote service and a reconnect listener for
that service:
final ImportRegistration registration =
remoteServiceAdmin.importService(endpointDescription);
final ReconnectServiceAdminListener reconnectListener
= new ReconnectServiceAdminListener(remoteServiceAdmin,
containerManager,
registration, endpointDescription);
context.registerService(RemoteServiceAdminListener.class.getName(),
reconnectListener, null);
2) inside the ReconnectListener I basically try to re-import
the service when the registration/connection fails:
public class ReconnectServiceAdminListener implements
RemoteServiceAdminListener {
private static final Duration RECONNECT_DELAY =
Duration.ofSeconds(10);
private final ReconnectJob reconnectJob;
private final EndpointDescription endpointDescription;
private final RemoteServiceAdmin remoteServiceAdmin;
private ImportRegistration registration;
private final IContainerManager containerManager;
public ReconnectServiceAdminListener(final
RemoteServiceAdmin remoteServiceAdmin,
final IContainerManager containerManager, final
ImportRegistration registration,
final EndpointDescription endpointDescription) {
this.remoteServiceAdmin = remoteServiceAdmin;
this.containerManager = containerManager;
this.registration = registration;
this.endpointDescription = endpointDescription;
reconnectJob = new ReconnectJob();
if (registration.getException() != null) {
reconnectJob.schedule(RECONNECT_DELAY.toMillis());
}
}
@Override
public void remoteAdminEvent(final RemoteServiceAdminEvent
e) {
final
org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.RemoteServiceAdminEvent
event =
(org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.RemoteServiceAdminEvent)
e;
if
(event.getEndpointDescription().isSameService(endpointDescription))
{
switch (event.getType()) {
case
RemoteServiceAdminEvent.IMPORT_UNREGISTRATION:
case RemoteServiceAdminEvent.IMPORT_ERROR:
reconnectJob.schedule(RECONNECT_DELAY.toMillis());
break;
}
}
}
class ReconnectJob extends Job {
public ReconnectJob() {
super("ReconnectJob");
}
@Override
protected IStatus run(final IProgressMonitor monitor)
{
final
org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.ImportRegistration
remoteServiceImportRegistration =
(org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.ImportRegistration)
registration;
final ID containerID =
remoteServiceImportRegistration.getContainerID();
final IContainer container =
containerManager.getContainer(containerID);
if (container != null) {
container.disconnect();
}
registration.close();
registration =
remoteServiceAdmin.importService(endpointDescription);
return Status.OK_STATUS;
}
}
}
The Thread count still increases with every run of the
ReconnectJob.
Any suggestions on how to solve this issue?
Thanks!
Bye Peter
Am 16.09.2017 um 05:03 schrieb
Scott Lewis:
Hi
Peter,
I'm assuming that you are using the generic provider.
I think you can do what you need to do by:
1) You can cast the ImportRegistration to
org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.ImportRegistration
2) Call
org.eclipse.ecf.osgi.services.remoteserviceadmin.RemoteServiceAdmin.ImportRegistration.getContainerID()
to get the container ID
3) Using the IContainerManager service (a singleton ecf
service) and the ID from 2 call: IContainer c =
containerManager.getContainer(id) to get the associated
container instance.
4) Call c.disconnect() to release the connection and
associated threads.
Scott
On 9/15/2017 7:27 AM, Peter Hermsdorf wrote:
Hi,
we encountered a problem while trying to import services
exported from a process running in a local VM (_not_ JVM).
The VM forwards the necessary port to the host machine.
As for the problem: RemoteAdminService#importService causes
a RemoteAdminServiceEvent.IMPORT_ERROR to be signalled and
the connections/threads opened due to the importService call
do not get closed, even though we call
ImportRegistration#close() on failed attempts. The latter
does not happen, if there is no one listening on the port at
all. Since, we have code that regularly calls importService
again for services, that should be, but are not currently
imported (according to
RemoteAdminService#getImportedEndpoints), we slowly
accumulate more and more threads.
The tcp connection to the local VM seems to be successful,
but due to issues regarding requested hostname and actual
hostname ECF (correctly) does not "connect the services"
(see https://dev.eclipse.org/mhonarc/lists//ecf-dev/msg07259.html
for a discussion of the "hostname problem - localhost !=
getCanonicalHostname()" in EndPointDescriptions; in this
case it is host::getCanonicalHostname() !=
VM::getCanonicalHostname())
So importService creates threads/connections, fails to
import, and even with a call to ImportRegistration#close()
does not clean up the threads/connections.
Any suggestions on how to solve this issue or more generally
handle this reconnect use-case are more than welcome!
Best regards,
Bye Peter
PS: we use the ecf generic provider on the latest ecf
release