Back-pressure

This section describes back-pressure in the 4.x drivers.

Neo4j 4.0 introduces client-side back-pressure. The concept of client-side back-pressure is that the client communicates with the remote server regarding how much data it is able to process and only requests additional data when it is ready to consume more.

The back-pressure concept is naturally compatible with Reactive programming. As a result, Reactive API support is added into all language drivers in 4.0 driver releases.

The Java driver’s Reactive API exposes a raw Publisher-Subscriber API, which is defined by reactive streams. The Java driver’s Reactive API is used with a reactive library, such as Project Reactor and/or RxJava.

The .NET uses the built-in System.Reactive. The JavaScript driver uses the RxJs library.

These libraries belong to the same reactive framework ReactiveX.

To use the drivers’ Reactive API, preliminary knowledge of reactive programming is necessary. Details of how to use Neo4j Reactive Driver API can be found in the Neo4j Drivers Manual v4.0.

However, back-pressure is not only limited to the drivers' Reactive APIs. All other APIs, such as simple and async, by default have back-pressure enabled when handling query execution results.

Table 1. How back-pressure is implemented in the different language driver session APIs
Simple API Async API Reactive API

Java driver

Record buffer

Record buffer

Raw Publisher-Subscriber API

.NET driver

Record buffer

Record buffer

Record buffer

Javascript driver

Not applicable

Record buffer

Record buffer

1. Back-pressure with Bolt v4.0 and record buffer

The Neo4j 4.0 server and drivers implement Bolt v4.0. One of the main features introduced in this Bolt version is pulling query results (records) in batches. In previous Bolt versions, the complete result set is always pulled in one batch from a server to a driver. Bolt v4.0 enables you to pull these results in multiple batches where the size of each can be defined by fetchSize. By default, the drivers use a fetchSize of 1000 records.

With the introduction of batching of records, drivers can implement client-side back-pressure. For each result, the driver keeps a record buffer of unconsumed records. The buffer size is the same as fetchSize for each batch. The pulling of records from the server is paused when the buffer is more than 70% full, and the record pulling is re-enabled once the buffer is less than 30% full. With the default fetchSize of 1000 records, record pulling is paused when more than 700 records are in the buffer and is resumed when the buffer drops below 300.

Example 1. Set default fetchSize on a driver and alter the default value on a session.
import org.neo4j.driver.AuthTokens;
import org.neo4j.driver.Config;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.Session;
import org.neo4j.driver.SessionConfig;
...

Config config = Config.builder().withFetchSize( 2000 ).build();
Driver driver = GraphDatabase.driver( uri, AuthTokens.basic( user, password ), config );

SessionConfig sessionConfig = SessionConfig.builder()
                                          .withDatabase( "neo4j" )
                                          .withFetchSize( 100 )
                                          .build();
try ( Session session = driver.session( sessionConfig ) ) {...}

2. Java driver Reactive API

The Java driver’s Reactive API exposes a very low-level Publisher-Subscriber API. As a result, it does not perform any kind of back-pressure by default. Instead, the driver users should make use of a reactive framework to utilize back-pressure. Depending on the reactive framework, the framework may apply back-pressure by pausing the data-pulling from a Neo4j server, or dropping data when there is too much to process.