0

Checking this tutorial: https://rderik.com/blog/understanding-swiftnio-by-building-a-text-modifying-server/

One thing I do not understand that the main point using NIO directly is to increase speed of a backend service.

But, when we has this pipe:

Client: hello
      |
      v
   Server
      |
      v
BackPressureHandler (Receives a ByteBuffer - passes a ByteBuffer)
      |
      v
UpcaseHandler(Receives a ByteBuffer - passes a [CChar])
      |
      v
VowelsHandler(Receives a [CChar] - passes a ByteBuffer)
      |
      v
ColourHandler(Receives a ByteBuffer - passes a ByteBuffer)
      |
      v
Client: receives
H*LL* (In green colour)

parameter gets transformed many times. In UpcaseHandler NIOAny -> ByteBuffer -> string -> CChar -> NIOAny

then in VowelsHandler again: NIOAny -> ByteBuffer -> string -> CChar -> NIOAny

What is the advantage to have so many independent handlers?

If server receive a 'flat' JSON, is it worth to process it with with JSONEncoder, if speed, each microseconds are critical? try JSONEncoder().encode(d2)

Or is it worth, is it common to implement own JSON processor. I.e. an event driven JSON parser?

János
  • 32,867
  • 38
  • 193
  • 353

1 Answers1

0

I think it's useful to use things like an UppercasingHandler when trying to learn and understand SwiftNIO. In the real world however, this is too fine grained for a ChannelHandler.

Typically, the use-case for a ChannelHandler is usually one of the following (not exhaustive):

  • a whole network protocol (example NIOSSLClientHandler which adds TLS for a client connection)
  • added value that may be useful with multiple protocols (such as the BackpressureHandler)
  • added value that may be useful for debugging (example NIOWritePCAPHandler)

So whilst the overhead of a ChannelHandler isn't huge, it is definitely not completely free and I would recommend not overusing them. Abstraction is useful but even in a SwiftNIO-based application or library we should try to express everything as ChannelHandlers in a ChannelPipeline.

The value-add of having something in a ChannelHandler is mostly around reusability (the HTTP/1, HTTP/2, ... implementations don't need to know about TLS), testability (we can test a network protocol without actually needing a network connection) and debuggability (if something goes wrong, we can easily log the inputs/outputs of a ChannelHandler).

The NIOWritePCAPHandler for example is a great example: In most cases, we don't need it. But if something goes wrong, we can add it in between a TLS handler and say the HTTP/2 handler(s) and we get a plaintext .pcap file without having to touch any code apart from the code that inserts it into the ChannelPipeline which can even be done dynamically after the TCP connection is already established.

There's absolutely nothing wrong with a very short ChannelPipeline. Many great examples have just a few handlers, for example:

TLS handler <--> network protocol handler(s) [HTTP/1.1 for example] <--> application handler (business logic)

Johannes Weiss
  • 52,533
  • 16
  • 102
  • 136
  • Thank you for your detailed answer. Would you use JSONEncoder() in ChannelHandler when speed is extremly important? Or is it any more advance solution? – János Aug 30 '22 at 20:28
  • 1
    @János I don't think this can be answered conclusively without benchmarking if the JSON encoding is actually your performance issue. I'll say a few things: 1. measure how much time you spend in JSON encoding, if it's significant, you may want to look into alternative JSON encoders in Swift. 2. JSON isn't the most efficient format to encode, if your performance problems stem from JSON encoding, can you maybe replace it with a different (probably binary) encoding format? – Johannes Weiss Aug 31 '22 at 21:34
  • 1
    An example of a different (and more performant) JSON en/decoder is https://github.com/swift-extras/swift-extras-json – Johannes Weiss Aug 31 '22 at 21:35