ReceiveActor Receive<T> in Akka.net is not working - c#

im new to Akka.net, im running on linux and using .NET Core 3.1, i have written a very simple code but it does not work and i dont know why.
this my program.cs where i created the ActorSystem and simply called another actor
using Akka.Actor;
namespace PBFT
{
class Program
{
static void Main(string[] args)
{
var MyActorSystem = ActorSystem.Create("ActorSystem");
var Primary = MyActorSystem.ActorOf<PrimaryActor>();
Primary.Tell("Test");
}
}
}
and this is the first actor that is supposed to receive the message and simply outputs it to the console
using Akka.Actor;
using Akka;
using Akka.Event;
namespace PBFT
{
class PrimaryActor : ReceiveActor
{
private readonly ILoggingAdapter log = Context.GetLogger();
public PrimaryActor()
{
Receive<string>(message => System.Console.WriteLine(message));
}
}
}
the problem is there are no errors and the message does not get processsed by the Actor, am i missing something ?

Messages to and between actors in Akka.NET are passed asynchronously. What happens in your example, is that you're Telling a message to an actor and exiting the program immediately afterwards, before actor got a chance to process the message.
You can either suspend main thread (using eg. Console.ReadLine()) in your example, or - if you need to be sure that actor had processed the message before going forward - use combination of actor.Ask(message, cancellationToken) on the caller side (which will return Task, that completes once actor sends a response back) and Sender.Tell(response) inside your actor's receive method:
class PrimaryActor : ReceiveActor
{
private readonly ILoggingAdapter log = Context.GetLogger();
public PrimaryActor()
{
Receive<string>(message => {
System.Console.WriteLine(message);
Sender.Tell(new object()); // or any other response you want
});
}
}
class Program
{
static async Task Main(string[] args)
{
var MyActorSystem = ActorSystem.Create("ActorSystem");
var Primary = MyActorSystem.ActorOf<PrimaryActor>();
await Primary.Ask<object>("Test", default(CancellationToken));
}
}

Related

C# gRPC with GrpcDotNetNamedPipes -- how to check if Client is connected to service?

I am using C# gRPC with GrpcDotNetNamedPipes to do interprocess communication on the same machine.
Currently, I am having a problem in that if my service is not set up, and I invoke a service request from my client side -- the client side just locks up waiting until the service is available.
I am unsure how to check if client has been connected to the service.
Example code below:
///Autogenerated gRPC code that contains COM API
public static partial class PluginCOM
{
public partial class PluginCOMClient : grpc::ClientBase<PluginCOMClient>
{
//Autogenerated code from protofile
//...
}
}
/// Client class that
public class PluginClient : PluginCOM.PluginCOMClient
{
public PluginClient() : base(new GrpcDotNetNamedPipes.NamedPipeChannel(".", "Service"))
{
}
public bool Test() => Test(new Empty()).Loaded;
}
public static class Tester
{
static void Test()
{
client = new PluginClient();
client.Test(); /// Deadlocks here and waits until service is available
}
}
Calling the Tester.Test() function dead locks when attempting to call client.Test().
I would like something like:
public static class Tester
{
static void Test()
{
client = new PluginClient();
if (/* code here to check if client is connected */)
{
client.Test();
}
}
}
I've had the same problem, but after looking at issues on official GitHub page finally found the solution:
https://github.com/cyanfish/grpc-dotnet-namedpipes/issues/17
By default connection timeout is set by Infinite, but you can set up timeout by yourself using NamedPipeChannelOptions:
public PluginClient() : base(new GrpcDotNetNamedPipes.NamedPipeChannel(".","Service",
new GrpcDotNetNamedPipes.NamedPipeChannelOptions { ConnectionTimeout = 350 }))
{
}

Masstransit How to make Advanced request / reply pattern

I have 3 micro-services as following communicating via masstransit/rabbitmq
I'd like that the Api makes request to the TransactionService but got the response from the PspService.
namespace API
{
//I wish to have something like this
PaymentForm form = await requestClient.GetResponse<PaymentForm>(new CreatePayment())
}
namespace TransactionService
{
public class CreatePaymentConsumer : IConsumer<CreatePayment>
{
public async Task Consume(ConsumeContext<CreatePayment> context)
{
context.Send<BuildPaymentForm>()
}
}
}
namespace PspService
{
public class BuildPaymentFormConsumer : IConsumer<BuildPaymentForm>
{
public async Task Consume(ConsumeContext<BuildPaymentForm> context)
{
context.Response<PaymentForm>() //how to make sure that the response will be sent to the API, but not to the caller (TransactionService)?
}
}
}
Please point me to the right way to make this communication pattern or a similar example, or the right part in the documentation.
You can copy the RequestId and ResponseAddress from the CreatePayment message to the message produced by the first consumer using the CreateCopyContextPipe method. There is also a built-in way to copy all headers to the outgoing message (which I've used below).
namespace TransactionService
{
public class CreatePaymentConsumer : IConsumer<CreatePayment>
{
public async Task Consume(ConsumeContext<CreatePayment> context)
{
var pipe = context.CreateCopyContextPipe();
await _otherHost.Publish(new BuildPaymentForm(...), pipe);
}
}
}
namespace PspService
{
public class BuildPaymentFormConsumer : IConsumer<BuildPaymentForm>
{
public async Task Consume(ConsumeContext<BuildPaymentForm> context)
{
await context.RespondAsync(new PaymentForm(...));
}
}
}
The first consumer will publish the command to the second consumer, copying all headers to the outbound message. The second consumer will then respond to the request initiator.

c#/core close application but allow a child process to continue running

I'm trying to handle events triggered by a MTA.
The MTA calls the following code/exe. It doesn't proceed until the exe exits.
I need the MTA to proceed (exe to exit), whilst the code in Process is still running.
I'm assuming that when I create the task, since it's a child process the main context completing terminates the child context.
I've also tried creating its as a new thread along with other methods.
Please could someone explain how I would achieve this?
namespace Test
{
class Program
{
static void Main(string[] args)
{
Task.Run(() => new Foo().Process(args));
}
}
class Foo
{
public async void Process(string[] args)
{
// do something
await Task.delay(200);
// do something
}
}
}
I think what you want is an async Main method this is now supported in .NET Core. This way you can await the processing and the process will stay open until the processing is finished.
Here is your sample changed to this approach. I increased the wait time to 5 seconds so it is more visible.
namespace ConsoleApp4
{
class Program
{
static async Task Main(string[] args)
{
await new Foo().Process(args);
}
class Foo
{
public async Task Process(string[] args)
{
// do something
await Task.Delay(5000);
// do something
}
}
}
}

Akka.net deadlocking issue with ActorSelection

Having an issue with akka.net. I need to access an actor which I have already created with a specific name. I can retrieve the actor from IActorContext but I am struggling to access it from the ActorSystem.
I have created a method called GetOrCreateActor which attempts to get the actor using ActorSelection. If it doesn't exist, the catch creates a new actor with the name. If it does exist, I want it to return the reference. However, it never returns from '.Result'. Assuming this could be some sort of deadlocking issue.
public static IActorRef GetOrCreateActor<T>(this ActorSystem actorSystem, string actorPath, string name = null) where T : ActorBase
{
try
{
return actorSystem.ActorSelection(actorPath).ResolveOne(TimeSpan.FromSeconds(1)).Result;
}
catch
{
return actorSystem.ActorOf(actorSystem.DI().Props<T>(), name);
}
}
Edit
I've tried to include a simplified version of the calling code below.
The actor system is created in an IOC container using AutoFac (ExampleActor is the ReceiveActor I am trying to access):
containerBuilder.RegisterAssemblyTypes(typeof(ExampleActor).Assembly).Where(x => x.Name.EndsWith("Actor"));
var lazyContainer = new Lazy<IContainer>(() => containerBuilder.Build());
containerBuilder.Register(c =>
{
var system = ActorSystem.Create("ExampleActorSystem");
new AutoFacDependencyResolver(lazyContainer.Value, system);
return system;
}).As<ActorSystem>().SingleInstance();
return lazyContainer.Value;
ActorSystem is then injected into another class, where I call the GetOrCreateActor method (via the Execute method):
public class ExampleCommand : IExampleCommand
{
private readonly ActorSystem _actorSystem;
public ExampleCommand(ActorSystem actorSystem)
{
_actorSystem = actorSystem;
}
public void Execute()
{
SendMessage();
}
private void SendMessage()
{
string message = new Message();
_actorSystem.GetOrCreateActor<ExampleActor>("akka://ExampleActorSystem/user/ExampleActor", "ExampleActor").Tell(message);
}
}
The above command would be called from a RESTful endpoint
public ExampleGetModule(IExampleCommand exampleCommand)
{
Get["/api/createExample"] = parameters =>
{
exampleCommand.Execute();
};
}
Your deadlocking issue looks more like it has to do with how you're using your container than it does Akka.NET:
var lazyContainer = new Lazy<IContainer>(() => containerBuilder.Build());
containerBuilder.Register(c =>
{
var system = ActorSystem.Create("ExampleActorSystem");
new AutoFacDependencyResolver(lazyContainer.Value, system);
return system;
}).As<ActorSystem>().SingleInstance();
In terms of what can go wrong here, self-referential Lazy<T> types are an infamous source of race-conditions. You should not be calling lazyContainer.Value inside of this registration method if the output of containerBuilder.Build depends on the input of containerBuilder.Register.
Last thing is to use step-through debugging to make sure that your application actually calls into the ResolveOne method here - if you're not getting a timeout exception back then it means that your application is deadlocking on producing the actor system (because of how DI is configured).

Progress update while WCF is executed

I have an ASP.NET 3.5 app consuming a C# WCF in an intranet.
The service executes three commands sequentially taking 2-3 mins each. I'd like to keep the user updated with the command that is running, for example, refreshing a label.
I'm not an expert on this matter so I'd like to know what is the best way to do this.
Thanks,
Ps. The service and the client are hosted in the same server using IIS 7.5.
EDIT
Well, I've been working on this for the past two days .. I'm not an expert :)
I'm following Eric's suggestion, use of WSHttpDualBinding and a callback function.
So, I was able to build a service using duplex binding and define a callback function, however I can't define the callback function on the client side, can you please shed some light on this.
namespace WCF_DuplexContracts
{
[DataContract]
public class Command
{
[DataMember]
public int Id;
[DataMember]
public string Comments;
}
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallbacks))]
public interface ICommandService
{
[OperationContract]
string ExecuteAllCommands(Command command);
}
public interface ICallbacks
{
[OperationContract(IsOneWay = true)]
void MyCallbackFunction(string callbackValue);
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class CommandService : ICommandService
{
public string ExecuteAllCommands(Command command)
{
CmdOne();
//How call my callback function here to update the client??
CmdTwo();
//How call my callback function here to update the client??
CmdThree();
//How call my callback function here to update the client??
return "all commands have finished!";
}
private void CmdOne()
{
Thread.Sleep(1);
}
private void CmdTwo()
{
Thread.Sleep(2);
}
private void CmdThree()
{
Thread.Sleep(3);
}
}
}
EDIT 2
This the client implementation,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Client.DuplexServiceReference;
using System.ServiceModel;
namespace Client
{
class Program
{
public class Callback : ICommandServiceCallback
{
public void MyCallbackFunction(string callbackValue)
{
Console.WriteLine(callbackValue);
}
}
static void Main(string[] args)
{
InstanceContext ins = new InstanceContext(new Callback());
CommandServiceClient client = new CommandServiceClient(ins);
Command command = new Command();
command.Comments = "this a test";
command.Id = 5;
string Result = client.ExecuteAllCommands(command);
Console.WriteLine(Result);
}
}
}
And the result:
C:\>client
cmdOne is running
cmdTwo is running
cmdThree is running
all commands have finished!
Use a duplex binding and update status in a callback.
EDIT*
You need to get a reference to the callback channel
public string ExecuteAllCommands(Command command)
{
var callback = OperationContext.Current.GetCallbackChannel<ICallbacks>();
CmdOne();
//How call my callback function here to update the client??
callback.MyCallbackFunctio("cmdOne done");
CmdTwo();
callback.MyCallbackFunctio("cmdTwo done");
//How call my callback function here to update the client??
CmdThree();
callback.MyCallbackFunctio("cmdThree done");
//How call my callback function here to update the client??
return "all commands have finished!";
}
You'll prolly want the service method to be void as to not time out
I would create a couple of operations. One to start the lengthy command, and another to get the status. If you have one operation that waits for the command to complete, you run into the problem of timeouts and have no way to figure out progress.

Categories