Folks,

I agree with Ivan that we can improve the user experience in Ignite
services by adding support for "middleware".
And as a first step, we need to pass the "caller context" to the service.

I see the following API options for reading this "context" inside a service:
(please see "API proposal" section in Jira [1] for full formatted examples)

1. Using a custom annotation (ServiceRequestContextResource) and
reading context attributes with a function.

    @ServiceRequestContextResource
    private Function<String, Object> ctxFunc;

    public void serviceMethod() {
        String login = (String)ctxFunc.apply("login");
    }

2. Using a new method of the existing ServiceContext.

    private ServiceContext svcCtx;

    public void init(ServiceContext svcCtx) {
        this.svcCtx = svcCtx;
    }

    public void serviceMethod() {
        String login = svcCtx.attribute("login");
        // and/or
        String login = (String)svcCtx.attributes().get("login");
    }


The next two options require wrapping Map<String, Object> into a new
ServiceRequestContext class.

3. Read context "wrapper" using special annotation and supplier.

    @ServiceRequestContextResource
    private Supplier<ServiceRequestContext> ctxSupplier;

    public void serviceMethod() {
        String login = ctxSupplier.get().attribute("login");
    }

4. Using the special static method of the "wrapper" class.

    public void serviceMethod() {
        String login = ServiceRequestContext.current().attribute("login");
    }

Let's discuss which one is the way to go.

[1] https://issues.apache.org/jira/browse/IGNITE-15572

вт, 12 окт. 2021 г. в 13:51, Ivan Daschinsky <ivanda...@gmail.com>:
>
> Hi, Val
>
> >>The examples you mentioned are more related to internal activities (e.g.,
> >> if authentication is handled by an Ignite server node, it can create its
> >> internal context for a connection - this is certainly reasonable). I'm
> only
> >> worried about exposing this to the end user.
>
> I'm talking about not Ignite auth, but external auth. Here I am considering
> Ignite Service Grid as a microservice platform.
> Authentication microservice can be not related to Ignite at all, but author
> of service may want to retrieve or authenticate user by user_id, that is
> provided in request headers or context in jwt token, for example.
>
> The same is for tracing or metrics. Ignite internal mechanisms here cannot
> help at all, because there is no context related to user's code.
>
> If we want to leave Ignite Service Grid as dump as possible, it is ok. But
> therefore it cannot compete with more functional variants.
>
> But just adding request headers at first step and custom interceptors
> (client and server side)  we can give to user's of Ignite Service Grid a
> lot of opportunities.
>
> There is an example of golang grpc middlewares -- see how many interesting
> use cases here:
> https://github.com/grpc-ecosystem/go-grpc-middleware
>
> вт, 12 окт. 2021 г. в 07:31, Valentin Kulichenko <
> valentin.kuliche...@gmail.com>:
>
> > Ivan,
> >
> > I'm a bit confused :) Unless I misread the initial suggestion, the idea is
> > to provide a public API to create the context. In other words, it will be
> > up to the end user to create this context properly, which affects the
> > business code - and that's exactly where I see an issue.
> >
> > The examples you mentioned are more related to internal activities (e.g.,
> > if authentication is handled by an Ignite server node, it can create its
> > internal context for a connection - this is certainly reasonable). I'm only
> > worried about exposing this to the end user.
> >
> > Maybe you can pick one of the use cases that you think would benefit from
> > this feature the most, and provide a little more detail? How would you like
> > to see the use case to be addressed and what is currently missing?
> >
> > Also, just to be clear: I'm not necessarily against the suggestion, and
> > it's highly unlikely that I will want to veto it if you or someone else
> > will decide to implement it. Just expressing my concerns.
> >
> > -Val
> >
> > On Sun, Oct 10, 2021 at 11:52 PM Nikolay Izhikov <nizhi...@apache.org>
> > wrote:
> >
> > > +1 to have service proxy context.
> > >
> > > > 11 окт. 2021 г., в 09:43, Ivan Daschinsky <ivanda...@gmail.com>
> > > написал(а):
> > > >
> > > > Val, Pavel both of you are right, but on the other hand there are some
> > > > other tasks
> > > >
> > > > 1. Distributed tracing.
> > > > 2. Custom metrics/measurements
> > > > 3. Auth and some related tasks (i.e. ingests full User info by calling
> > > some
> > > > auth service in middleware).
> > > >
> > > > Do you both think that this is a good idea in business code?
> > > >
> > > > Without this functionality, our service grid cannot compete with grpc
> > and
> > > > others as microservice framework, unfortunately.
> > > >
> > > > But if we introduce limited support for this "request headers", it can
> > > > drastically improves this aspects of our service grid framework.
> > > >
> > > >
> > > > пн, 11 окт. 2021 г. в 00:48, Valentin Kulichenko <
> > > > valentin.kuliche...@gmail.com>:
> > > >
> > > >> I agree with Pavel. The suggested approach is indeed utilized quite
> > > >> frequently, but it's inherently error-prone.
> > > >>
> > > >> The main issue is that it creates implicit assumptions about the
> > > behavior
> > > >> of both the service and the user's code. For example, if the user's
> > code
> > > >> must provide a username, what if it doesn't? I assume it will get an
> > > error,
> > > >> which is very counterintuitive. Even more importantly, how should one
> > > learn
> > > >> about this requirement in the first place? It is not reflected in the
> > > API
> > > >> in any way - and that's a big problem.
> > > >>
> > > >> The fact that the service implementor needs to update the API methods
> > > when
> > > >> such requirements are introduced is actually a good thing, in my
> > > opinion.
> > > >> This forces the developer to stop and think about how the updated API
> > > >> should look like and how to make sure it's backward-compatible (or
> > not,
> > > in
> > > >> case the new requirements are mandatory). Doing this through an
> > external
> > > >> context is basically the equivalent of saying "let the end user deal
> > > with
> > > >> this". Not a good practice, in my view.
> > > >>
> > > >> Conversely, passing everything exclusively via method arguments
> > > guarantees
> > > >> that:
> > > >>
> > > >>   - The user's code is always compliant with the service contract. You
> > > >>   can't "forget" to pass something to the service.
> > > >>   - Any changes in the service contract (backward-compatible or
> > > otherwise)
> > > >>   are explicitly reflected in the API.
> > > >>
> > > >>
> > > >> -Val
> > > >>
> > > >>
> > > >> On Sun, Oct 10, 2021 at 6:21 AM Pavel Tupitsyn <ptupit...@apache.org>
> > > >> wrote:
> > > >>
> > > >>> Ivan,
> > > >>>
> > > >>> Yes, this approach is used by some other systems, and still, I don't
> > > like
> > > >>> it very much.
> > > >>> Let's hear more opinions.
> > > >>>
> > > >>> On Sat, Oct 9, 2021 at 9:00 PM Ivan Daschinsky <ivanda...@gmail.com>
> > > >>> wrote:
> > > >>>
> > > >>>> Hi.
> > > >>>> Pavel T., Ok, http rest dosn't have the clean design, in your
> > opinion.
> > > >>>>
> > > >>>> But what about grpc? The same?
> > > >>>>
> > > >>>> As for me, it is ok to pass additional parameters as list of
> > key-value
> > > >>>> pairs with keys as strings and values as bytearrays or strings. It
> > is
> > > >> ok
> > > >>> to
> > > >>>> allow user to set up middlewares for services and allow to enrich
> > > >> request
> > > >>>> context in this middlewares. It is very common approach everywhere
> > and
> > > >> is
> > > >>>> very useful in distributed systems. The use cases are so obvious,
> > > >> aren't
> > > >>>> they?
> > > >>>>
> > > >>>>
> > > >>>>
> > > >>>> сб, 9 окт. 2021 г., 20:14 Pavel Tupitsyn <ptupit...@apache.org>:
> > > >>>>
> > > >>>>> Pavel,
> > > >>>>>
> > > >>>>> Thanks for the explanation, I understand the use cases.
> > > >>>>>
> > > >>>>>> in REST service, he can set such parameters in request headers
> > > >>>>>
> > > >>>>> I don't consider HTTP-based services as a good example of a
> > > >>>>> clean architecture.
> > > >>>>> Data can be passed in URL parameters, in headers, and in body, and
> > > >> each
> > > >>>> of
> > > >>>>> those ways has its own limitations.
> > > >>>>> There is no obvious correct way to do things.
> > > >>>>>
> > > >>>>>>> Ambient state is not obvious and the API looks confusing even
> > > >>> though I
> > > >>>>> understand our services stack quite well both in Java and .NET
> > > >>>>>> Can you clarify please?
> > > >>>>>
> > > >>>>> The proposed API adds a "side channel" for the data.
> > > >>>>> Some is passed as arguments, which is obvious, and some becomes
> > > >>> magically
> > > >>>>> available on the server side through some external context.
> > > >>>>> - You have to know about the context
> > > >>>>> - You have to understand that the context is only available during
> > > >> the
> > > >>>>> method call (can't use it in some background logic)
> > > >>>>>
> > > >>>>> In my opinion, this is a bit too clever. I'm a fan of the
> > functional
> > > >>>>> programming approach where everything you need is passed as
> > > >> arguments.
> > > >>>>>
> > > >>>>>
> > > >>>>>
> > > >>>>> On Fri, Oct 8, 2021 at 4:29 PM Pavel Pereslegin <xxt...@gmail.com>
> > > >>>> wrote:
> > > >>>>>
> > > >>>>>> Igor, Pavel.
> > > >>>>>>
> > > >>>>>>> Why can not a user implement such context on application level? I
> > > >>>>>> believe Ignite provides all necessary tools for that.
> > > >>>>>> The user wants to trace the source of the service call. For
> > > >> example,
> > > >>> a
> > > >>>>>> service must log the name of the user who made the calls of the
> > > >>>>>> service. For now, there's no possibility to do that without
> > > >> modifying
> > > >>>>>> the service interface and implementation. Moreover, the user must
> > > >>>>>> modify all methods of service to pass this parameter. For example,
> > > >> in
> > > >>>>>> REST service, he can set such parameters in request headers, why
> > we
> > > >>>>>> can't provide such usability in Ignite.
> > > >>>>>>
> > > >>>>>>> This will reduce the performance of all calls
> > > >>>>>> This feature is optional, if the context is not passed - then
> > > >> there's
> > > >>>>>> shouldn't be any performance difference.
> > > >>>>>>
> > > >>>>>>> Ambient state is not obvious and the API looks confusing even
> > > >>> though
> > > >>>> I
> > > >>>>>> understand our services stack quite well both in Java and .NET
> > > >>>>>> Can you clarify please?
> > > >>>>>>
> > > >>>>>> пт, 8 окт. 2021 г. в 15:46, Pavel Tupitsyn <ptupit...@apache.org
> > >:
> > > >>>>>>>
> > > >>>>>>> Agree with Igor.
> > > >>>>>>>
> > > >>>>>>> I'm not sure this feature is a good fit for Ignite.
> > > >>>>>>> Ignite should not be responsible for such a high-level concept,
> > > >>> this
> > > >>>>>> should
> > > >>>>>>> be on the application side instead.
> > > >>>>>>>
> > > >>>>>>> - As Eduard noted, it is hard to make this type-safe
> > > >>>>>>> - Ambient state is not obvious and the API looks confusing even
> > > >>>> though
> > > >>>>> I
> > > >>>>>>> understand our services stack quite well both in Java and .NET
> > > >>>>>>> - This will reduce the performance of all calls
> > > >>>>>>>
> > > >>>>>>> On Fri, Oct 8, 2021 at 3:44 PM Igor Sapego <isap...@apache.org>
> > > >>>> wrote:
> > > >>>>>>>
> > > >>>>>>>> Hi guys,
> > > >>>>>>>>
> > > >>>>>>>> Why can not a user implement such context on application level?
> > > >>>>>>>> I believe Ignite provides all necessary tools for that. User
> > > >> can
> > > >>>> just
> > > >>>>>>>> implement such a context as user type and pass it to services
> > > >>> they
> > > >>>>>>>> need. Are the arguments why would Ignite need a separate
> > > >> feature
> > > >>>>>>>> for such a use case?
> > > >>>>>>>>
> > > >>>>>>>> Best Regards,
> > > >>>>>>>> Igor
> > > >>>>>>>>
> > > >>>>>>>>
> > > >>>>>>>> On Fri, Oct 8, 2021 at 2:17 PM Eduard Rakhmankulov <
> > > >>>>>> erixon...@gmail.com>
> > > >>>>>>>> wrote:
> > > >>>>>>>>
> > > >>>>>>>>> I am not aware .NET capabilities, but as I can see service
> > > >> must
> > > >>>> be
> > > >>>>>>>>> implemented in *java* and even if can't serialize other that
> > > >>> Map
> > > >>>> on
> > > >>>>>> .NET
> > > >>>>>>>>> side, on java side we can wrap this map with provided
> > > >>>> TypedContext
> > > >>>>>>>> (context
> > > >>>>>>>>> should be convertible from map in this case).
> > > >>>>>>>>> That leads to a situation when Java can use TypedContext but
> > > >>>> other
> > > >>>>>>>> clients
> > > >>>>>>>>> can't. I believe that the majority of services users are
> > > >> using
> > > >>>> Java
> > > >>>>>> and
> > > >>>>>>>> it
> > > >>>>>>>>> should be taken in accordance.
> > > >>>>>>>>>
> > > >>>>>>>>> P.S. I think it is possible to send plain objects from .NET
> > > >>>> context
> > > >>>>>> to
> > > >>>>>>>>> cluster.
> > > >>>>>>>>>
> > > >>>>>>>>> Best regards, Ed
> > > >>>>>>>>>
> > > >>>>>>>>> On Fri, 8 Oct 2021 at 14:40, Pavel Pereslegin <
> > > >>> xxt...@gmail.com>
> > > >>>>>> wrote:
> > > >>>>>>>>>
> > > >>>>>>>>>> Hi, Eduard!
> > > >>>>>>>>>>
> > > >>>>>>>>>> Thanks for your feedback.
> > > >>>>>>>>>>
> > > >>>>>>>>>> The idea sounds very good, but don't forget about the
> > > >>> platform
> > > >>>>>>>> services.
> > > >>>>>>>>>> For example, we may call Java service from .Net and
> > > >>> vice-versa.
> > > >>>>> I'm
> > > >>>>>>>>>> not sure if the context can be implemented as a custom
> > > >> class
> > > >>>>>> (instead
> > > >>>>>>>>>> of Map/Dictionary) in this case.
> > > >>>>>>>>>>
> > > >>>>>>>>>> пт, 8 окт. 2021 г. в 14:21, Eduard Rakhmankulov <
> > > >>>>>> erixon...@gmail.com>:
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> Hi, Pavel
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> Is it possible to provide type-safe API for
> > > >>>>> ServiceProxyContext ?
> > > >>>>>>>>>>> I think constructions like int arg1 =
> > > >>> ctx.attribute("arg1");
> > > >>>>> are
> > > >>>>>>>> error
> > > >>>>>>>>>>> prone.
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> Can we make something like this :
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> //Signature with two generic params which allow the
> > > >>> compiler
> > > >>>> to
> > > >>>>>> check
> > > >>>>>>>>>>> if the service will be called with the wrong type
> > > >> context.
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> public <T extends ContextedWith<CtxType>, CtxType> T
> > > >>>>>>>>>>> serviceProxyTyped(ClusterGroup prj, String name, Class<?
> > > >>>> super
> > > >>>>> T
> > > >>>>>>>
> > > >>>>>>>>>>> srvcCls, CtxType optCtx, boolean sticky, long timeout)
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> //new interface which services with scoped context should
> > > >>>>>> implement
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> public interface ContextedWith<T> {
> > > >>>>>>>>>>> T getCtx();
> > > >>>>>>>>>>> }
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> // implementation can delegate to Map-like context or be
> > > >>>> POJO.
> > > >>>>>>>>>>> interface MyServiceContext {
> > > >>>>>>>>>>> int getArg1();
> > > >>>>>>>>>>> String getUserId();
> > > >>>>>>>>>>> }
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> class MyService implements
> > > >> ContextedWith<MyServiceContext>
> > > >>> {
> > > >>>>>>>>>>> void doThings() {
> > > >>>>>>>>>>> MyServiceContext ctx = getCtx();
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> System.out.println("ctx.getArg1() = " + ctx.getArg1());
> > > >>>>>>>>>>> }
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> @Override public MyServiceContext getCtx() {
> > > >>>>>>>>>>> return ServiceProxyContext.current();
> > > >>>>>>>>>>> }
> > > >>>>>>>>>>> }
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> WDYT?
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> Best regards, Ed.
> > > >>>>>>>>>>>
> > > >>>>>>>>>>> On Fri, 8 Oct 2021 at 13:26, Pavel Pereslegin <
> > > >>>>> xxt...@gmail.com>
> > > >>>>>>>>> wrote:
> > > >>>>>>>>>>>
> > > >>>>>>>>>>>> Hello Igniters!
> > > >>>>>>>>>>>>
> > > >>>>>>>>>>>> I want to implement a feature to support a custom
> > > >>> "caller"
> > > >>>>>> context
> > > >>>>>>>> in
> > > >>>>>>>>>>>> ignite services (see example in ticket description
> > > >> [1]).
> > > >>>>>>>>>>>>
> > > >>>>>>>>>>>> Sometimes, when using Ignite services, it becomes
> > > >>> necessary
> > > >>>>> to
> > > >>>>>> pass
> > > >>>>>>>>>>>> custom parameters from the "request source" to the
> > > >>> service.
> > > >>>>>> This is
> > > >>>>>>>>>>>> most commonly used to track the origin of a service
> > > >> call
> > > >>>>> (user
> > > >>>>>> id,
> > > >>>>>>>>>>>> request id, session id eg see this user question [2]).
> > > >>>>>>>>>>>> At the moment, the only way to pass such parameters to
> > > >> a
> > > >>>>>> service is
> > > >>>>>>>>> by
> > > >>>>>>>>>>>> adding argument(s) to all called methods of the
> > > >> service,
> > > >>>>> which
> > > >>>>>>>> makes
> > > >>>>>>>>>>>> the code messy and also complicates development and
> > > >>>>>> maintenance.
> > > >>>>>>>>>>>>
> > > >>>>>>>>>>>> I propose letting the user set a custom context for the
> > > >>>>> service
> > > >>>>>>>> proxy
> > > >>>>>>>>>>>> and implicitly pass that context to the methods being
> > > >>>> called.
> > > >>>>>> This
> > > >>>>>>>>>>>> function should not affect the execution of service
> > > >>> methods
> > > >>>>> in
> > > >>>>>> any
> > > >>>>>>>>> way
> > > >>>>>>>>>>>> unless the user has specified a context.
> > > >>>>>>>>>>>>
> > > >>>>>>>>>>>> An example of using the proposed API [1].
> > > >>>>>>>>>>>> PoC (except thin clients) [3].
> > > >>>>>>>>>>>>
> > > >>>>>>>>>>>> WDYT?
> > > >>>>>>>>>>>>
> > > >>>>>>>>>>>> [1] https://issues.apache.org/jira/browse/IGNITE-15572
> > > >>>>>>>>>>>> [2]
> > > >>>>>>>>>>>>
> > > >>>>>>>>>>
> > > >>>>>>>>>
> > > >>>>>>>>
> > > >>>>>>
> > > >>>>>
> > > >>>>
> > > >>>
> > > >>
> > >
> > https://stackoverflow.com/questions/57459071/apache-ignite-service-grid-service-call-context
> > > >>>>>>>>>>>> [3] https://github.com/apache/ignite/pull/9440
> > > >>>>>>>>>>>>
> > > >>>>>>>>>>
> > > >>>>>>>>>
> > > >>>>>>>>
> > > >>>>>>
> > > >>>>>
> > > >>>>
> > > >>>
> > > >>
> > > >
> > > >
> > > > --
> > > > Sincerely yours, Ivan Daschinskiy
> > >
> > >
> >
>
>
> --
> Sincerely yours, Ivan Daschinskiy

Reply via email to