question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

io.r2dbc.spi.R2dbcNonTransientResourceException: Unknown message header 0x3 and readable bytes is 23 on command phase

See original GitHub issue
  • MariaDB 10
  • spring-tx-5.2.0.Rc1
  • r2dbc-mysql-0.2.0.M2
  • kotlin-1.3.41

exception:

Caused by: io.r2dbc.spi.R2dbcNonTransientResourceException: Unknown message header 0x3 and readable bytes is 23 on command phase
	at io.github.mirromutth.r2dbc.mysql.message.server.ServerMessageDecoder.decodeCommandMessage(ServerMessageDecoder.java:233) ~[r2dbc-mysql-0.2.0.M2.jar:?]
	at io.github.mirromutth.r2dbc.mysql.message.server.ServerMessageDecoder.decodeMessage(ServerMessageDecoder.java:82) ~[r2dbc-mysql-0.2.0.M2.jar:?]
	at io.github.mirromutth.r2dbc.mysql.message.server.ServerMessageDecoder.decode(ServerMessageDecoder.java:54) ~[r2dbc-mysql-0.2.0.M2.jar:?]
	at io.github.mirromutth.r2dbc.mysql.client.MessageDuplexCodec.channelRead(MessageDuplexCodec.java:100) ~[r2dbc-mysql-0.2.0.M2.jar:?]
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374) ~[netty-transport-4.1.38.Final.jar:4.1.38.Final]

test code:

val c = 30
val data = Flux.range(0, c).map {
    User(email = "integration-test$it@mail.com", password = "[PASSWORD]")
}.flatMap(userRepository::insert)

val n = transactionalOperator.transactional(data).blockLast()
println(n)
fun insert(user: User): Mono<Int> = Mono.defer {
    dc.execute("INSERT INTO DUIC_USER(email,password,created_at,updated_at) VALUES(:email,:password,NOW(),NOW())")
            .bind("email", user.email)
            .bind("password", user.password)
            .fetch()
            .rowsUpdated()
}

The code failed to run under spring reactive transaction. Normal operation without transaction.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:6 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
mp911decommented, Aug 31, 2019

we cannot (should not) expect to issue multiple commands on a single connection because that’s not the way relational databases work.

The multiple command statement relates to something like:

Connection c = …;

c.createStatement("SELECT id FROM person")
    .execute().flatMap(result -> result.map((row, metadata) -> row.get(0, Integer.class))
    .flatMap(id -> c.createStatement("INSERT INTO my_table VALUES(" + id+")").execute());

That is, executing commands while another result stream is active. The reason why we should not expect this to work is because the command response (response stream of rows) isn’t fully consumed and issuing commands can lock up the connection because of response buffers and backpressure demand.

Another issue is concurrent command queueing (concurrent subscriptions). That is what we typically call thread-safety in imperative programming. If a command on a connection is still active (e.g. running an insert or changing transaction state (BEGIN/COMMIT/ROLLBACK)), it would be good if connections could queue commands so a queued command only is executed if the previous one was completed (assuming that pipelining is not supported).

That is somewhat tricky to achieve because it requires a recursive queue and potentially deferred command creation if commands require a connection-state-specific identifier. I did this for R2DBC SQL Server. R2DBC Postgres has a similar implementation.

The background of concurrent subscriptions is that a transaction manager can issue a commit (transaction cleanup) either onComplete or onCancel. While onComplete allows for synchronization (typically via Mono.usingWhen or Flux.usingWhen), onCancel() has no synchronization.

A case for such behavior is Mono<Object> singleFromFlux = transactionalOperator.transactional(data).next();. .next() or .take() operators cancel their upstream subscription to send a completion signal downstream. With usingWhen(…), cancellation typically leads to a commit because the transaction was successful. usingWhen receives a cancellation and issues a commit. If a subsequent invocation wants to operate on the connection, the connection may be still busy with transaction cleanup.

0reactions
mirromutthcommented, Sep 16, 2019

It solved by PR #52 , target version is 0.3.0.M3.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Io.R2Dbc.Spi.R2Dbcnontransientresourceexception - ADocLib
Caused by: io.r2dbc.spi.R2dbcNonTransientResourceException: Unknown message header 0x3 and readable bytes is 23 on command phase at.
Read more >
Warning C6385 - Microsoft Learn
Invalid data: accessing buffer-name, the readable size is size1 bytes, but size2 bytes may be read: Lines: x, y ...
Read more >
How do I get rid of this warning C6385 reading invalid data
Warning C6385 Reading invalid data from 'CRdr': the readable size is '(unsigned int)*108+4' bytes, but '216' bytes may be read. C++. Expand ▽....
Read more >
r2dbc-mysql from mirromutth - Coder Social
Caused by: io.r2dbc.spi.R2dbcNonTransientResourceException: Unknown message header 0x3 and readable bytes is 23 on command phase at ...
Read more >
C6385 Reading invalid data from 'ss': the readable size is '352 ...
(Each stringstream must be 176 bytes wide in your environment, based on the specific warning text.) You must not do that: -1 is...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found