I have plan to convert all my grpc service to armeria-grpc but i have an issue, armeria execute service logic directly in event loop and i should handle blocking part manually, this take a lot of from me.
Now want to now what is your reason for using event loop for execute service logic?
Thanks and sorry for my bad english.
We run callbacks directly on the event loop to optimize performance in fully asynchronous servers, which armeria encourages. However it can indeed get tedious for large services with lots of blocking logic to run callbacks in executors so I just sent #1525 to add an option so callbacks are run in the blocking executor.
Thanks @iEAmi and @anuraaga for suggestion and fix. :+1:
Thanks for this new option 馃憤. You save my life 馃榿
I am an armeria fan. Armeria is awsome
@iEAmi I'm happy to hear that you are enjoying Armeria in your project! What kind of service did you build using it? What pros and cons did you find from Armeria? Do you use it in production? If so, for what company? :smile:
We are working on a fintech project in 'Poolito' (mean Money in persian) and using armeria for exposing grpc/rest api to clients, android, ios, web.
Armeria built-in unframed-grpc and grpc-web and simple decorating api help us to use a single method for all kind of requests.
Learning armeria is easy貙 our developers learn to use armeria in less than a day and start writing code.
Some part of our services now work on armeria in production. We have a plan to convert all services to armeria.
That's awesome! Please feel free to let us know if you find any missing features or shortcomings. We'd be happy to address them. :bowing_man: Cheers!
We will tell you about missing features surely.
Thank you 馃檹馃徎
When I am using useBlockingTaskExecutor on GrpcServiceBuilder sometimes a problem occur.
client receive INTERNAL: Half-closed without a request.
I figure it out that problem can be from ArmeriaSeverCall, because endOfStream method invoked before messageRead and this make problem.
I think race occur between threads.
Thanks for the report and sorry for the issue it does seem easy to run into.
@trustin what do you think of making blocking executor an EventLoopGroup? I haven't thought of it in detail but I think a large separate event loop group allows running blocking logic while also allowing pulling out a single event loop so for cases like this all callbacks run on the same (non-I/O thread) in order.
I didn't have a chance to take a close look yet, but shouldn't we fix the race condition so that a user can complete the response from whatever thread he or she wants?
It's not about the server code but the requests from the client - so it's about which thread is used by the framework, not user. ArmeriaServerCall has never had any dependencies on what thread is used by user code.
The data from the client will come as message, then end of stream. We notify the callbacks for message and end of stream using the blocking executor, which means end of stream may have its callback run first if they're different threads, which isn't allowed. Ordering of callbacks is well defined.
I guess it's pretty normal for a blocking server to handle each incoming request on a separate dedicated thread (hence # of threads = number of concurrent requests), so running all callbacks for a given stream on the same non-I/O thread seems natural. The simplest way to implement it is taking advantage of EventLoop I think, otherwise a Queue with flushing could be used - but that's an event loop I think ;)
Thanks for explanation. I'd prefer blockingTaskExecutor to stay as Executor to give users more freedom although it would complicate the fix in this case...
Ah I forgot users can set blockingTaskExecutor too :) Will try to fix it with a Queue then. I think it's similar to grpc-java.
Thanks, @anuraaga :-)
While I'm working on a 1.0 issue which is "Make a blockingTaskExecutor a SchedulerExecutorService", this issue came to my mind.
I'm wondering if we still need to make blockingTaskExecutor an EventLoopGroup.
The constructor of ScheduledThreadPoolExecutor does not allow me to restrict the maximum number of threads to be created, so I think I need to use different implementation for that.
But before that, if we need all callbacks using blocking tasks run in order, I think I have to use a different approach.
I think it's worth to provide blockingTaskExecutor which runs the tasks in order when the tasks are provided from the same EventLoop. WDYT?
Yeah, we could provide an alternative executor implementation with such a feature, although I'm not sure if it has to be the default behavior. How about leaving this issue as closed, opening a new one and referring to this issue there? The original problem has been fixed already.
Have thought about it and it was a bad idea that makes blockingTaskExecutor an EventLoopGroup because a user can specify his/her own executor and the thread pool never times out even when they are not used.
Thanks to @trustin, I can use ScheduledThreadPoolExecutor for "Make a blockingTaskExecutor a SchedulerExecutorService", so let me use that. 馃槃
Most helpful comment
We are working on a fintech project in 'Poolito' (mean Money in persian) and using armeria for exposing grpc/rest api to clients, android, ios, web.
Armeria built-in unframed-grpc and grpc-web and simple decorating api help us to use a single method for all kind of requests.
Learning armeria is easy貙 our developers learn to use armeria in less than a day and start writing code.
Some part of our services now work on armeria in production. We have a plan to convert all services to armeria.