nats-io / nats.java

Java client for NATS
Apache License 2.0
563 stars 153 forks source link

NATS option duration based properties do not accept duration string format #1182

Closed PeterJakubik closed 1 month ago

PeterJakubik commented 1 month ago

Observed behavior

Hi I would like to change the NATS cleanupinterval by setting the property in springboot application yaml like

io.nats.client.cleanupinterval: PT10S

Reason is, that the publisher replays in ~10 secs.

It looks like the NatsAutoConfiguration doesn't reflect this cleanupinterval interval set in properties.

Expected behavior

I expect the property in springboot application.yaml is reflected for NatsConnection options

Server and client version

nats-spring 0.5.7

Host environment

springboot

Steps to reproduce

sample

scottf commented 1 month ago

The property currently expects milliseconds so this will work for now:

io.nats.client.cleanupinterval: 10000

I have created this PR to handle the duration string: https://github.com/nats-io/nats.java/pull/1183

PeterJakubik commented 1 month ago

Thanks for quick reply. I suppose I miss something obvious for NATS autoconfiguration.

I have a demo that has configures NATS cleanupinterval to 10000 https://github.com/PeterJakubik/nats-properties/blob/main/src/main/resources/application.yml#L5

But once the NATS Connection is injected the cleanupinterval https://github.com/PeterJakubik/nats-properties/blob/ac0abbe33896be9945573517da5f88caa8ab32de/src/main/java/com/example/demo/DemoApplication.java#L35 is still 5 sec

Why is the NatsAutoConfiguration not picking the cleanupinterval from application.yml ?

scottf commented 1 month ago

@PeterJakubik Did you see the unit tests I added? The options object is definitely built correctly. So that leaves 2 things.

  1. The options, although set, are not used properly or how/where you expect them to be used, or there is a different property being exercised, something like that.
  2. Whatever spring mechanism you are using is not working.
PeterJakubik commented 1 month ago

I have seen the unit tests and they are correct. I just can't see how java properties like io.nats.client.cleanupinterval get loaded into NatsConnection. I tried adding value io.nats.client.cleanupinterval=12000 to nats-spring-samples/autoconfigure-sample application.properties. I expect this value to be reflected into NatsConnection but this doesn't happen.

Please bear with me, how could I configure the io.nats.client.cleanupinterval property value in spring in such a way, that the NatsConnection will use it?

scottf commented 1 month ago

Cleanup interval is a timer set on requests. When a request is made, a future goes into a map. On the interval, the thread wakes up and checks the map, looking for any futures that have expired (see NatsRequestCompletableFuture) and cleans them out of the map so as to avoid memory leaks.

What function/behavior are your trying to set?

PeterJakubik commented 1 month ago

I have burst request-reply scenario, when there are lot of requests but slow replays (the replay comes in 10-20 sec). In my logs I see "Future cancelled, response not registered in time, check connection status." When I looked into requestFutureInternal NATS method, I see it creates a NatsRequestCompletableFuture with default timeout options.getRequestCleanupInterval() and that is by default 5 seconds. So I assume that NatsRequestCompletableFuture timeouts after 5 secs if there is no reply and my app replays take longer.

I was trying to increase the NatsRequestCompletableFuture timeout to more like 20 sec by setting the io.nats.client.cleanupinterval to 20 and see if that helps.

scottf commented 1 month ago

Use JetStreamOptions to change the request timeout, which defaults to 2 seconds. For example:

JetStreamOptions jso = JetStreamOptions.builder().requestTimeout(Duration.ofSeconds(10)).build();

You can create a JetStreamManagement context like so:

JetStreamManagement jsm = connection.jetStreamManagement(jso);

You can create a JetStream context from the connection

JetStream js = connection.jetStream(jso);

or from the management instance, it uses whatever options you created the management with

JetStream js = jsm.jetStream();