How use Wire with Flow in client gRPC? - kotlin

i need stream of a service gRPC with Wire and need use Flow on client, but executeBlocking() do not provide method with return via Flow, need implementation manual via flow emits?

I think you wanna use execute, instead of executeBlocking() and find some way to transform the Channels into Flows? Or just start a new Flow from the blockingGet value?
flow {
emit(value)
}

Related

Using NServiceBus in a synchronous API

I'm exposing an API to a vendor where that vendor requires the API to be synchronous. I however would like to use NServiceBus on the backend of it to make good use of our other architecture.
Is there a product/framework that can be used to do support this flow?
Are there any thoughts/considerations in choosing this approach?
The API is as said synchronous where we will transform the request a bit and then put it on an NServiceBus queue for further processing by other systems.
After the message has been sent to a queue we should wait for the other system to complete its actions and be woken up again when the reply message is received.
Pseudo code:
void APICall(String someMessage) {
var msgBusMessage = new { json = someMessage, ID = Guid.NewID() };
NServiceBus.EnqueueMessage(msgBusMessage);
var returnMessage = NServiceBus.WaitForReplyMessageWithID(msgBusMessage.ID);
return returnMessage;
}
NServiceBus has a feature called Callbacks which is designed to handle this type of interaction. It works almost exactly like the snippet you have provided. You send a request via NServiceBus and then get a Task that will eventually contain the response. You can await that task and return the result to the synchronous API.
To set it up:
Add a reference to the NServiceBus.Callbacks package (in both the sender and the receiver endpoints)
Enable callbacks by calling endpointConfiguration.EnableCallbacks(). If an endpoint returns replies but does not request request synchronous callbacks then you should use endpointConfiguration.EnableCallbacks(makesRequests: false)
Any endpoint that makes callback requests should be made Uniquely Addressable endpointConfiguration.MakeInstanceUniquelyAddressable(someUniqueIdThatSurvivesRestarts). This allows the response message to be routed to the specific endpoint instance that is waiting for it.
In the caller, use the following var response = await endpoint.Request<ResponseMessage>(new RequestMessage { ... })
In the receiver create a handler for RequestMessage and return context.Reply(new ResponseMessage {...})
You can read more about this feature (including some caveats around when you should and shouldn't use it) in the documentation. There is also a sample showing the feature in use.

Is there a way to dynamically change destination in Spring Cloud Stream Reactive method?

I know that if I implement SC Stream Function in Spring reactive way, I can't send DLQ like traditional imperative way.
To do this, I am trying to manually change the Destination in the MessageHeader so that the message goes to the DLQ Topic.
However, if an error occurs, I want to send a message to the zombie Topic using the onErrorContinue method, but that doesn't work.
Shouldn't I produce it in onErrorContinue?
input.flatMap { sellerDto ->
// do something..
}.onErrorContinue { throwable, source ->
log.error("error occured!! ${throwable.message}")
source as Message<*>
Flux.just(MessageBuilder.withPayload(String(source.payload as ByteArray)).setHeader("spring.cloud.stream.sendto.destination","zombie").build())
}
No, since with reactive function the unit of work is the entire stream (not individual item). I provide more details here.
That said, you can inject StreamBridge which is always available as a bean and use it inside of your filter or any other applicable reactive operator. Basically streamBridge.send("destination", Message)

ServiceStack: Reinstate pipeline when invoking a Service manually?

As a follow-up to this question, I wanted to understand how my invoking of a Service manually can be improved. This became longer than I wanted, but I feel the background info is needed.
When doing a pub/sub (broadcast), the normal sequence and flow in the Messaging API isn't used, and I instead get a callback when a pub/sub message is received, using IRedisClient, IRedisSubscription:
_subscription.OnMessage = (channel, msg) =>
{
onMessageReceived(ParseJsonMsgToPoco(msg));
};
The Action onMessageReceived will then, in turn, invoke a normal .NET/C# Event, like so:
protected override void OnMessageReceived(MyRequest request)
{
OnMyEvent?.Invoke(this, new RequestEventArgs(request));
}
This works, I get my request and all that, however, I would like it to be streamlined into the other flow, the flow in the Messaging API, meaning, the request finds its way into a Service class implementation, and that all normal boilerplate and dependency injection takes place as it would have using Messaging API.
So, in my Event handler, I manually invoke the Service:
private void Instance_OnMyEvent(object sender, RequestEventArgs e)
{
using (var myRequestService = HostContext.ResolveService<MyRequestService>(new BasicRequest()))
{
myRequestService.Any(e.Request);
}
}
and the MyRequestService is indeed found and Any called, and dependency injection works for the Service.
Question 1:
Methods such as OnBeforeExecute, OnAfterExecute etc, are not called, unless I manually call them, like: myRequestService.OnBeforeExecute(e) etc. What parts of the pipeline is lost? Can it be reinstated in some easy way, so I don't have to call each of them, in order, manually?
Question 2:
I think I am messing up the DI system when I do this:
using (var myRequestService = HostContext.ResolveService<MyRequestService>(new BasicRequest()))
{
myRequestService.OnBeforeExecute(e.Request);
myRequestService.Any(e.Request);
myRequestService.OnAfterExecute(e.Request);
}
The effect I see is that the injected dependencies that I have registered with container.AddScoped, isn't scoped, but seems static. I see this because I have a Guid inside the injected class, and that Guid is always the same in this case, when it should be different for each request.
container.AddScoped<IRedisCache, RedisCache>();
and the OnBeforeExecute (in a descendant to Service) is like:
public override void OnBeforeExecute(object requestDto)
{
base.OnBeforeExecute(requestDto);
IRedisCache cache = TryResolve<IRedisCache>();
cache?.SetGuid(Guid.NewGuid());
}
So, the IRedisCache Guid should be different each time, but it isn't. This however works fine when I use the Messaging API "from start to finish". It seems that if I call the TryResolve in the AppHostBase descendant, the AddScoped is ignored, and an instance is placed in the container, and then never removed.
What parts of the pipeline is lost?
None of the request pipeline is executed:
myRequestService.Any(e.Request);
Is physically only invoking the Any C# method of your MyRequestService class, it doesn't (nor cannot) do anything else.
The recommended way for invoking other Services during a Service Request is to use the Service Gateway.
But if you want to invoke a Service outside of a HTTP Request you can use the RPC Gateway for executing non-trusted services as it invokes the full Request Pipeline & converts HTTP Error responses into Typed Error Responses:
HostContext.AppHost.RpcGateway.ExecuteAsync()
For executing internal/trusted Services outside of a Service Request you can use HostContext.AppHost.ExecuteMessage as used by ServiceStack MQ which applies Message Request Request/Response Filters, Service Action Filters & Events.
I have registered with container.AddScoped
Do not use Request Scoped dependencies outside of a HTTP Request, use Singleton if the dependencies are ThreadSafe, otherwise register them as Transient. If you need to pass per-request storage pass them in IRequest.Items.

Implement user authentication with gRPC

I'm looking to implement simple user authentication with my dart gRPC server + client and am struggling to find samples on how to achieve this properly.
So my problems are the following:
How do I add the user authentication data (JWT) to API calls that require authentication on the client?
How to I handle this data on the server?
I assume that on the client, metadata is the way to go, but is there a way to add the authentication data automatically for each call?
For the server, I assume that interceptors are the way to go, but how do I specify interceptors for specific services only (since not all API calls require authentication)?
is there a way to add the authentication data automatically for each call?
You can supply the default CallOptions with the options parameter in the generated client constructor.
You can use that to add authorization info to all your calls. If you need to perform async work for each call (for instance, to check if the token is still valid and optionally refresh it), you could add a MetadataProvider which gets invoked for each call.
how do I specify interceptors for specific services only (since not all API calls require authentication)?
The interceptor gets access to a ServiceMethod, which contains a name. So you could check that to only invoke an interceptor on some methods:
extension OnlyInterceptSome on Interceptor {
Interceptor limitTo(Set<String> endpoints) {
return (call, method) {
// Skip the check if we don't care about the method.
if (!endpoints.contains(method.name)) return null;
// Invoke the regular interceptor otherwise
return this(call, method);
};
}
}

Is it possible to use a MuleClient to send/dispatch a message directly to a flow without a specific inbound endpoint?

I have a flow that I usually reference elsewhere with just a flow-ref component. I would like to test this flow by making a call directly to it with a MuleClient. Is this possible? If so, can you provide an example. Here's what I have, but it doesn't work. Obviously, it's missing the protocol that would go before 'processChanges', but I don't know what that would be in this case.
MuleClient client = new MuleClient(muleContext);
client.dispatch("processChanges", payload, null);
When running from a FunctionalTestCase you can use the method runFlow(String flowName, MuleEvent event) to execute the flow with that MuleEvent as input. HTH.