ID | IEP-79 |
Author | Pavel Pereslegin |
Sponsor | |
Created | 13 Oct 2021 |
Status | DRAFT |
When implementing microservices, users are often face with the task of separating the business logic from the common "middleware" logic.
An example of a typical “middleware” task is auditing calls to business service methods (the system must understand which user called which methods and with what result).
Modern frameworks such as gRPC and Apache Thrift provide a very flexible API for implementing request interceptors, with which you can solve almost any middleware task.
Apache Ignite does not provide any mechanisms for solving such problems in general. The user needs to implement it himself, which often results in a lot of boilerplate code.
The Ignite Service Grid must support the following capabilities:
public interface ServiceCallInterceptor extends Serializable { public default void onInvoke(ServiceInterceptorContext ctx) throws ServiceInterceptException { // No-op. } public default void onComplete(@Nullable Object res, ServiceInterceptorContext ctx) throws ServiceInterceptException { // No-op. } public default void onError(Throwable err, ServiceInterceptorContext ctx) { // No-op. } }
ServiceCallInterceptor security = new ServiceCallInterceptor() { @Override public void onInvoke(ServiceInterceptorContext ctx) throws ServiceInterceptException { // Check permission before execution of the method. if (!CustomSecurityProvider.get().access(ctx.method(), ctx.attribute("sessionId"))) throw new SecurityException("Method invocation is not permitted"); } } ServiceCallInterceptor audit = new ServiceCallInterceptor() { @Override public void onInvoke(ServiceInterceptorContext ctx) { // Record an event before execution of the method. AuditProvider.get().recordStartEvent(ctx.method(), ctx.attribute("sessionId")); } @Override public void onComplete(@Nullable Object res, ServiceInterceptorContext ctx) { AuditProvider.get().recordFinishEvent(ctx.method(), ctx.attribute("sessionId")); } @Override public void onError(Throwable err, ServiceInterceptorContext ctx) { AuditProvider.get().recordError(ctx.method(), ctx.attribute("sessionId"), err.getMessage()); } } // Set context parameters for service proxy. ServiceCallContext ctx = ServiceCallContext.builder().put("sessionId", sessionId).build(); ServiceConfiguration svcCfg = new ServiceConfiguration() .setName("service") .setService(new MyServiceImpl()) .setMaxPerNodeCount(1) .setInterceptors(Arrays.asList(security, audit)); // Deploy service. ignite.services().deploy(svcCfg); MyService proxy = ignite.services().serviceProxy("service", MyService.class, false, ctx, 0); // A business method call to be intercepted. proxy.placeOrder(order1); proxy.placeOrder(order2);
// Describe project risks, such as API or binary compatibility issues, major protocol changes, etc.
// Links to various reference documents, if applicable.