Hello, Kevin
as a reminder
we are observing strange problems after upgrading from milo 0.2.5
to 0.3.3 suddenly client freezes when i disconnect from serveror do read operations.
I prepared
the
refined example of when I observe thread block (even when reading data),
In example below there are 3 version of code of which second (main_stuck) stucks,
and this is behaviour that changed from milo 0.2.5. to milo 0.3.3,
sadly our coide relies heavily on building chains of completable futures, so before I start rewriting all our code to follow approach # 1 or # 3,
I want to ask if such new behaviour is normal for milo 0.3.3 and will be forever or its just bug ?
btw: must say that for me these stucks are kinda unexpected I would rather see error messages if api usage is wrong
@Slf4j
public class DemoApplication {
private static final String url = "opc.tcp://qub-emulator:12345/example";
@SneakyThrows
public static void main_works(String[] args) {
OpcUaClient client = getClient();
client.connect().get();
debugServerInfo(client);
client.disconnect().get();
log.info("work is done");
}
@SneakyThrows
public static void main_stuck(String[] args) {
OpcUaClient client = getClient();
//doesn't work - stucks on reading nodes
CompletableFuture<?> connected = client.connect();
connected
.thenApply((a) -> debugServerInfo(client))
.thenApply((a) -> disconnect(client))
.get();
log.info("work is done");
}
@SneakyThrows
public static void main_works_with_chain_and_executor(String[] args) {
OpcUaClient client = getClient();
CompletableFuture<?> connected = client.connect();
ExecutorService executor = Executors.newSingleThreadExecutor(new DefaultThreadFactory("background", true));
connected
.thenApplyAsync((a) -> debugServerInfo(client), executor)
.thenApplyAsync((a) -> disconnect(client), executor)
.get();
log.info("work is done");
}
private static Object disconnect(OpcUaClient client) {
try {
return client.disconnect().get();
} catch (Exception e) {
log.error("cannot disconnect", e);
return e;
}
}
@SneakyThrows
private static OpcUaClient getClient() {
Optional<EndpointDescription> firstEndpoint = DiscoveryClient.getEndpoints(url).get()
.stream()
.filter(t -> t.getSecurityMode() == MessageSecurityMode.None)
.findFirst();
log.info("using endpoint {}", firstEndpoint.get());
OpcUaClientConfigBuilder configBuilder = OpcUaClientConfig.builder()
.setApplicationName(LocalizedText.english("some opc-ua client"))
.setApplicationUri("urn:some:client")
.setIdentityProvider(new AnonymousProvider())
.setEndpoint(firstEndpoint.get())
.setRequestTimeout(uint(5000))
.setCertificateValidator(new InsecureCertificateValidator());
OpcUaClientConfig config = configBuilder.build();
return new OpcUaClient(config, UaStackClient.create(config));
}
@SneakyThrows
private static Object debugServerInfo(OpcUaClient client) {
log.info("about to debug some server info");
ServerNode serverNode = client.getAddressSpace().getObjectNode(Identifiers.Server, ServerNode.class).get();
ServerState state = serverNode.getServerStatusNode().get().getState().get();
DateTime dateTime = serverNode.getServerStatusNode().get().getCurrentTime().get(5, TimeUnit.SECONDS);
log.info("state {}", state);
log.info("dateTime {}", dateTime);
return null;
}
}