Unexpected getResultStream() behavior - onClose not called

Hi,

I am using getResultStream() and just found what I think is an unexpected behavior.

Using Hibernate 5.4.18.Final;

This code should print “closed”, but it doesn’t.

var query = em.createNativeQuery("select 1");
Stream<Object> stream = query.getResultStream();
stream = stream.onClose(() -> System.out.println("closed"));
stream.close();
// nothing printed

We can check this using a regular java stream:

var stream = Arrays.asList(new int[] {}).stream();
stream = stream.onClose(() -> System.out.println("closed"));
stream.close();
// prints closed

I think the problem is related to the class StreamDecorator.
It seems this class tries to deal with closeHandlers, but I don’t think this class is needed at all.
Acording to Stream specs, we can add many closeHandlers to a stream, and they will be all executed in the order they were added.
It seems the developer misunderstood that, thinking there would be just one closeHandler for a stream, and he tried to deal with the possibility of someone add another closeHandler.
As you can see, we can register many closeHandlers, so it seems the standard Java implementation can handle this.

var stream = Arrays.asList(new int[] {}).stream();
stream = stream.onClose(() -> System.out.println("closed 1"));
stream = stream.onClose(() -> System.out.println("closed 2"));
stream.close();
// prints closed 1
// prints closed 2

Looking at AbstractProducedQuery.stream() method, which calls StreamDecorator:

		final Stream<R> stream = new StreamDecorator(
				StreamSupport.stream( spliterator, false ),
				scrollableResults::close
		);
		return stream;
	}

It seems this would be enough (didn’t check).

return StreamSupport.stream( spliterator, false ).onClose(scrollableResults::close);

Best regards,

Fabiano

PS:

Just tested the code and confirmed you don’t need StreamDecorator.
This class can be removed safely and we will get the expected behavior (ScrollableResultsImpl.close() will be called, and also any post appended closeHandlers).

I am new to this forum. Is this the right place to report bugs and/or to proppose code changes?

2 Likes

Hello.
We are experiencing some issues after migrating Hibernate to version 5.4.17 (with Spring Boot update).
The connection pool get exhausted and I found this is caused by our query.stream.onClose(session::close) not being called.
After some investigation, I came to the exact same conclusion as you: the problem seems to be in the StreamDecorator:

	@Override
	public Stream<R> onClose(Runnable closeHandler) {
		this.closeHandler = closeHandler;
		return this;
	}

The closeHandler is replaced by the new one, while in AbstractPipeline:

sourceStage.sourceCloseAction =
                (existingHandler == null)
                ? closeHandler
                : Streams.composeWithExceptions(existingHandler, closeHandler);

There’s indeed a handler composition mecanism.

Did you manage to get any attention on this issue ? Or did you submit a PR ?

Regards,
Jérôme

1 Like

We are having the same issue as you, has anyone been able to get some help from the hibernate team?

Just came across this issue while testing a streaming data pipeline. It does indeed look like StreamDecorator can be completely removed as the OP states. Couldn’t find a way to report this issue or submit a PR though. In the meantime, I noticed that adding a no-op flatMap immediately after the onClose that we register ensures that the runnable is called. I’m still not able to figure out “how” this works though.

Example.

stream.onClose(runnable).flatMap(Stream::of).close();

ends up actually invoking the runnable. Would love to hear thoughts on why this is working and if it’s reliable enough as a workaround till this is fixed.

If you think this is a bug, please create an issue in the issue tracker(https://hibernate.atlassian.net) with a test case(https://github.com/hibernate/hibernate-test-case-templates/blob/master/orm/hibernate-orm-5/src/test/java/org/hibernate/bugs/JPAUnitTestCase.java) that reproduces the issue.

Ideally, you would also create a pull request that includes the test in the Hibernate testsuite and a fix. Take a look at past pull requests to understand what needs to be done: https://github.com/hibernate/hibernate-orm/pull/3680

On it. Will send a PR once done.