I'm not clear on `ktor` vs `kotlinx.rpc` The rpc ...
# ktor
u
I'm not clear on
ktor
vs
kotlinx.rpc
The rpc library seems to give me a way to create server as well and then in ktor there's is integration with this, but it also asks for port So if I integrate the kotlinx.rpc into ktor, do I have 2 servers running? If so, does that make sense?
a
Hi! Save idea as having multiple connectors. You route the grpc into one port, regular HTTP traffic into another. Integration only hooks into Ktor's lifetime, so that you don't need to start/stop grpc server manually
u
but at that point, do I even need the ktor envelope? if grpc is all my communication (its a microservice)
a
No, you don't, that's why you can also just spin up the server yourself https://kotlin.github.io/kotlinx-rpc/grpc-server.html
u
I see, so I only would wrap it in ktor if I have other uses for ktor, like idk, serving some static html etc, right?
a
Yep
u
Okay but in practise in a larger company, is this common to have it standalone? Or is there an envelope something like spring boot because they also need kafka and db and what not? (In microservice context - I'm a backend noob)
a
Depends on the needs. Having fully standalone grpc service is common for small services. If you have a monolith - booting it up with spring is not uncommon either
u
Not monolith, just a microservice that needs to say access database and post something to kafka queue - would that warrant the spring boot in your mind?
a
Yeah, I don't see a reason why not I was just mentioning general examples
s
It's very common to only have a microservice receiving messages from grpc with database and kafka. Similar when you just need Kafka + database. I consider it best practice. It'll be much more lightweight and efficient.
👍 1
u
but I assume in pratcise you probably have some sort of homegrown wrapper around it to make the setup more convenient?
s
For Kafka I use this, arrow-kt.io/learn/coroutines/suspendapp/kafka TL;DR SuspendApp is a
runBlocking
that hooks into OS signals (SIGTERM/SIGINT) and thus binds structured concurrency to the process. This allows you to just rely on coroutines and structured concurrency for cleanup so you can rely on any rxjava/project reactor, or future based SDK and integration them seamlessly into coroutines. Sometimes I have a small homegrown wrapper to wrap callback based systems into Channel/Flow but it depends on the SDKs and integrations you need.
u
I'm mostly hinting at database work i.e. the hikari connection pooling etc, or generally to just expose a main function and "do anything" seems like it would yield divergence across teams, no?
or maybe all the other thing i'd miss if I didnt wrap it in spring boot for example - auth, tracing, di, all the config stuff
s
Ah, it kind-of depends on the teams, company, tech stack, etc. In couple of companies I've build internal libraries (homegrown wrappers) around SDKs to enforce a certain pattern like "provide these configurations, and then implement this lambda" and everything is provided for you. Sometimes it's just an internal library providing preconfigured hikari pools, kafka setups, etc. In rarer occasions it's just a set of guidelines because the use-cases differentiate too much.
u
didnt you then reinvent ktor at that point?
s
or maybe all the other thing i'd miss if I didnt wrap it in spring boot for example - auth, tracing, di, all the config stuff
I rarely use Spring Boot, and re-using stuff or splitting stuff from Ktor is easier than with Spring. So often a common module for Ktor can be re-used without Ktor.
didnt you then reinvent ktor at that point?
No, not at all. It's typically a common library pulled out of Ktor services.
u
right, but that means it need the ktor envelope to be viable?
s
I'm not entirely sure what you mean by that 🤔
u
I'm playing with kotlinx.rpc, I have a proto definition, the kx.rpc plugin spits out interface and models I implement the service interface and then they suggest
Copy code
fun main() {
    val server = GrpcServer(8080) {
        services {
            registerService<ImageRecognizer> { ImageRecognizerImpl() }
        }
    }

    server.start()
    server.awaitTermination()
}
to launch the thing i.e. to not wrap it with ktor or spring boot. It's nice that it's possible but -- my question is, should I do this? is it reasonable for production? Or should I always wrap it in ktor or spring boot or whatever
a
The answer is - depends on what you want 🤷
u
I'm just learning and I'm trying to figure out what's common in the industry The use case is a microservice
s
There is no one-fits-all answer to this question. Should you do this? It depends. Is it reasonable for production? Yes absolutely. Many other languages do this too. Or should I always wrap it in ktor or spring boot or whatever. It depends. If you find this easiest for your stack and don't mind paying the overhead of running Spring then sure. For Ktor I'm not sure I really see the point though.
u
Is it reasonable for production? Yes absolutely. Many other languages do this.
but aren't you then missing all the logging tracing stuff?
s
No, Spring and Ktor piggy back on OpenTelemetry. It works pretty much the same with or without Spring/Ktor.
u
Well sure but I need to handroll it, I cant just
Copy code
fun main() {
    val server = GrpcServer(8080) {
        services {
            registerService<ImageRecognizer> { ImageRecognizerImpl() }
        }
    }

    server.start()
    server.awaitTermination()
}
and call it a production ready service, can I? (I mean usually, in a professional company)
s
OpenTelemetry relies on zero code automatic instrumentation so you can call that a production service if you properly setup OpenTelemetry Java Agent.
u
hmm aha
a
I know, and this is great! But no one can give you a more precise answer. The industry standard is to answer the question "What do I need and why do I need that?" first - build later If you are just playing around - try both and see for yourself what fits better the project you are trying to build Do you need logging? Why? Do you need DI? Why? Do you need Kafka? Why? Until you answer these - any other answer is meaningless
☝️ 1
u
well my reasoning is that, if all 3 are actually necessary, should I take advantage of the ktor/springboot which would give me those automatically? (via config)
or rather, what's your intuition threshold to switch over from the stock thing
a
There is no good answer for that. The decision is on you and your team, based on your project and your needs I know you want a tool that will help you decide what and when to use, but the only reasonable tool is your own experience projected onto the problem you are solving. And this involves trial and error, we can't answer that for you, because there is no right answer, or right threshold
u
So you'd not considered it a mistake to wrap grpc service impl in ktor if I need logging & db access & kafka?
a
Let's put it this way If you are learning - there are no mistakes. You are exploring, and if you use ktor/spring just for this, but you get more knowledge from this setup - it's a win If you are a developer who is responsible for a technical decision in a project - your biggest mistake is not knowing why one is better than the other and just using it for the sake of using it
u
😄 I know, you can only answer so much generically, what's why I'm trying to suss out your intuition
a
And I'm trying to tell you that intuition can't work without project requirements Needs logging is not a requirement. Requirement is "we need to monitor crashes, RPS rates, etc." How do we use logs? What tools do we use to analyse them? Are they compatible with OpenTelemetry or should we use a different one? Which framework supports logging tools? How? This can go on for a while
what's why I'm trying to suss out your intuition
Let's not do this, please This is a support channel for Ktor-related topics, not CS learning I'm happy to help with questions and discuss topics, but not to act as a lecturer, there are other resources for that
u
yea no problem, thank you