-
Notifications
You must be signed in to change notification settings - Fork 70
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
java.io.IOException: Broken pipe
occurring on client calls with empty bodies
#515
Comments
java.io.IOException: Broken pipe
occurring on client calls with empty bodies
The fact that the body is empty is normal on requests/responses that transmit all their data through metadata. The fact that the client raises an exception is not. |
This is interesting to look at. I guess other issues are coming into play here. If I keep the service modification that you've made @ahjohannessen in your repro but adjust the code to this: package com.example
import smithy4s.hello._
import cats.effect._
import cats.effect.syntax.resource._
import cats.implicits._
import org.http4s.implicits._
import org.http4s.ember.server._
import org.http4s._
import com.comcast.ip4s._
import smithy4s.http4s.SimpleRestJsonBuilder
import org.http4s.ember.client.EmberClientBuilder
import org.http4s.client.Client
object HelloWorldImpl extends HelloWorldService[IO] {
def hello(
name: String,
town: Option[String]
): IO[HelloOutput] =
IO.pure { HelloOutput("hello") }
def hello2(
name: String,
age: Option[Int],
town: Option[String]
): IO[Hello2Output] =
IO.pure { Hello2Output("hello2") }
}
object Routes {
private val example: Resource[IO, HttpRoutes[IO]] =
SimpleRestJsonBuilder.routes(HelloWorldImpl).resource
private val docs: HttpRoutes[IO] =
smithy4s.http4s.swagger.docs[IO](HelloWorldService)
val all: Resource[IO, HttpRoutes[IO]] = example.map(_ <+> docs)
}
abstract class Setup extends IOApp.Simple {
// client middleware
val authMiddleware: org.http4s.client.Middleware[IO] = { client =>
Client { req =>
client.run(
req.withHeaders(
headers.Authorization(Credentials.Token(AuthScheme.Bearer, "TOKEN"))
)
)
}
}
val client = EmberClientBuilder.default[IO].build.map { client =>
SimpleRestJsonBuilder(HelloWorldService)
.clientResource(
authMiddleware(client),
Uri.unsafeFromString("http://127.0.0.1:9000")
)
}
val run = (client, Routes.all).tupled.flatMap { case (client, routes) =>
for {
hs <- client
_ <- EmberServerBuilder
.default[IO]
.withPort(port"9000")
.withHost(host"0.0.0.0")
.withHttpApp(routes.orNotFound)
.build
_ <- clientOp(hs).toResource
} yield ()
}.use_
def clientOp(hs: HelloWorldService[IO]): IO[Unit]
}
object FastServer extends Setup {
def clientOp(hs: HelloWorldService[IO]): IO[Unit] = IO.unit
}
object Hello2 extends Setup {
def clientOp(hs: HelloWorldService[IO]): IO[Unit] =
hs.hello2("hey!").void
}
object Hello extends Setup {
def clientOp(hs: HelloWorldService[IO]): IO[Unit] =
hs.hello("hey!").void
}
object Broken extends Setup {
def clientOp(hs: HelloWorldService[IO]): IO[Unit] =
hs.hello("hey!") *> hs.hello2("hey 2!").void
} Ran all 3 (Hello, Hello2 and Broken) with a script: > ./benchmark.sh
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
HTTP/1.1 POST http://127.0.0.1:9000/hello/hey! body=""
HTTP/1.1 200 OK body="{"message":"hello"}"
HelloOutput(hello)
real 0m7.283s
user 0m19.039s
sys 0m1.558s
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
HTTP/1.1 POST http://127.0.0.1:9000/hello2/hey! body="{}"
HTTP/1.1 200 OK body="{"message":"hello2"}"
Hello2Output(hello2)
real *0m35.766s*
user 0m13.703s
sys 0m1.017s
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
HTTP/1.1 POST http://127.0.0.1:9000/hello/hey! body=""
HTTP/1.1 200 OK body="{"message":"hello"}"
HTTP/1.1 POST http://127.0.0.1:9000/hello2/hey%202! body=""
[error] java.io.IOException: Broken pipe
[error] at java.base/sun.nio.ch.FileDispatcherImpl.write0(Native Method)
[error] at java.base/sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:62)
[error] at java.base/sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:132)
[error] at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:97)
[error] at java.base/sun.nio.ch.IOUtil.write(IOUtil.java:60)
[error] at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.finishWrite(UnixAsynchronousSocketChannelImpl.java:602)
[error] at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.finish(UnixAsynchronousSocketChannelImpl.java:199)
[error] at java.base/sun.nio.ch.UnixAsynchronousSocketChannelImpl.onEvent(UnixAsynchronousSocketChannelImpl.java:217)
[error] at java.base/sun.nio.ch.KQueuePort$EventHandlerTask.run(KQueuePort.java:312)
[error] at java.base/sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:113)
[error] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
[error] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
[error] at java.base/java.lang.Thread.run(Thread.java:833)
[error] at delay @ fs2.io.net.SocketCompanionPlatform$AsyncSocket.$anonfun$write$1(SocketPlatform.scala:137)
[error] at async @ fs2.io.net.SocketCompanionPlatform$AsyncSocket.go$2(SocketPlatform.scala:131)
[error] at flatMap @ fs2.io.net.SocketCompanionPlatform$AsyncSocket.go$2(SocketPlatform.scala:141)
[error] at modify @ org.http4s.ember.server.internal.Shutdown$$anon$1.<init>(Shutdown.scala:83)
[error] at flatten$extension @ org.http4s.ember.server.internal.Shutdown$$anon$1.<init>(Shutdown.scala:71)
[error] at apply @ org.http4s.ember.server.EmberServerBuilder.$anonfun$build$2(EmberServerBuilder.scala:177)
[error] stack trace is suppressed; run 'last Compile / runMain' for the full output
[error] (Compile / runMain) java.io.IOException: Broken pipe
real 0m5.969s
user 0m13.843s
sys 0m0.969s What's interesting is that
I'm still looking into it |
To be honest, it feels like it's an issue outside of smithy4s scope: fs2 or http4s related Like if the the calls to the client, in succession, consumed (or not) a stream and we end up in an invalid state. calling |
but it could also be our usage of http4s and fs2 in the client that does this |
@daddykotex What happens if you use http2 in ember server? |
it has no effect unfortunately |
@daddykotex It might be related to this http4s/http4s#4935 |
Ok, this is definitely a bug in ember. Switching to blaze fixes the issue. I'm not sure if it's related to the one you referred too but it's good to know anyway. |
Fixed in the 0.17.0 release |
Seems like there is a bug in how empty body is handled. I have a repro here. The smithy spec show cases differences in payload. Details are found here.
The text was updated successfully, but these errors were encountered: