Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
  • Dec 07 11:49
    IgorFedchenko commented #4085
  • Dec 07 10:31
    IgorFedchenko commented #4085
  • Dec 07 08:36
    IgorFedchenko commented #4085
  • Dec 06 20:57
    IgorFedchenko commented #4085
  • Dec 06 20:32
    IgorFedchenko commented #4085
  • Dec 06 20:01
    IgorFedchenko commented #4085
  • Dec 06 19:55
    IgorFedchenko commented #4085
  • Dec 06 16:22
    Aaronontheweb labeled #3997
  • Dec 06 16:22
    Aaronontheweb closed #3997
  • Dec 06 16:20
    IgorFedchenko commented #3997
  • Dec 06 16:08
    IgorFedchenko commented #4085
  • Dec 06 15:50
    Aaronontheweb assigned #4085
  • Dec 06 15:50
    Aaronontheweb labeled #4085
  • Dec 06 15:50
    Aaronontheweb labeled #4085
  • Dec 06 15:49
    Aaronontheweb closed #4032
  • Dec 06 14:58
    IgorFedchenko commented #4032
  • Dec 06 14:57
    IgorFedchenko opened #4085
  • Dec 05 17:21
    Aaronontheweb synchronize #4079
  • Dec 05 17:20
    Aaronontheweb labeled #4084
  • Dec 05 17:20
    Aaronontheweb labeled #4084
me-slove
@me-slove
actorselection is probably a reference. in which case you'd be back to the closure problem
Stephen Riley
@stephen-riley
I built the code first just using await httpClient.GetAsync()...
@me-slove , I've tried closing over it, too, and it still didn't work. Which is weird to me, cuz I figured if I'd closed over it, I'd get all the context linked to it and be fine.
me-slove
@me-slove
inside the same code block it should work though. that seems a little odd
Stephen Riley
@stephen-riley
Agreed, @me-slove , it is quite odd. I just re-tested that, still doesn't work.
var self = Self;
var context = Context;

httpClient.GetAsync(req.Url).ContinueWith(responseTask =>
{
    var mylogger = context.ActorSelection("/user/ConsoleLogger");
    var response = responseTask.Result;
    var duration = stopwatch.Elapsed.TotalMilliseconds;
    var msgResponse = new AkkaBlaster.Dto.WebResponse
    {
        StatusCode = response.StatusCode,
        Duration = duration
    };

    mylogger.Tell("message");
},
TaskContinuationOptions.AttachedToParent & TaskContinuationOptions.ExecuteSynchronously);
Onur Gumus
@OnurGumus
@stephen-riley can you actually try to resolve the selection by calling Resolve ?
Stephen Riley
@stephen-riley
The actor mylogger definitely receives the message, but it is from deadLetters, instead of from this httpclient actor.
@OnurGumus , I don't know about Resolve(), but I will try that!
Onur Gumus
@OnurGumus
ActorSelection returns a selection , not an actor ref. You can get an actorRef by calling Resolve on the Selection.
Stephen Riley
@stephen-riley
Do you mean ResolveOne()?
Onur Gumus
@OnurGumus
which may fail if no such actor found.
yes that one
Stephen Riley
@stephen-riley
k, let me try
Onur Gumus
@OnurGumus
I would also move the resolution outside of your lambda.
there is no need to resolve it there. You can resolve before.
me-slove
@me-slove
I haven't looked at the code for Context but what you are seeing for sure is that it is losing itself across the task boundary. It must be that it is derived instead of a variable
Stephen Riley
@stephen-riley
It must be that it is derived instead of a variable
Yeah, @me-slove , looking that way.
@OnurGumus , interestingly, waiting 1 second on the ResolveOne() returned null. Waiting 10 seconds (totally arbitrary) resulted in a good reference.
Onur Gumus
@OnurGumus
that's odd.
Stephen Riley
@stephen-riley
however, still shows all messages as coming from deadLetters. :worried:
I verified with the Identify message that the path is fine.
I think I'm gonna just pull down source and start tracing in. Clearly I have more to understand about the inner workings of Akka.NET when using the TPL patterns. :smile:
me-slove
@me-slove
protected static IActorContext Context
{
get
{
var context = InternalCurrentActorCellKeeper.Current;
if (context == null)
throw new NotSupportedException(
"There is no active ActorContext, this is most likely due to use of async operations from within this actor.");
            return context.ActorHasBeenCleared ? null : context;
        }
    }
it got screwy on the paste but it is definitely derived. here's the code https://github.com/akkadotnet/akka.net/blob/dev/src/core/Akka/Actor/ActorBase.cs
hectorcaban
@hectorcaban
Since I am creating multiple child actors .. how do I do child actors with wildcard routes. ?
Stephen Riley
@stephen-riley
@me-slove, after tracing into the code, I can confirm that InternalCurrentActorCellKeeper.Current is null when inside the ContinueWith() lambda.
So I guess it's just safe to assume that inside ContinueWith() (for this TPL-style IO handling), you have to be explicit because you simply don't have any current actor context for the calls to work with. shrugs
so that's why I have to explicitly specify a sender in Tell(), because of how the normal Tell() is implemented:
        public static void Tell(this IActorRef receiver, object message)
        {
            var sender = ActorCell.GetCurrentSelfOrNoSender();
            receiver.Tell(message, sender);
        }
It would be nice to solve this in the library, but short of making the "current self" concept a stack instead of a singleton, I don't see how to do that nicely. Oh well.
@me-slove and @OnurGumus, thanks for all your help! :smiley:
me-slove
@me-slove
I using chaining a lot so I generally pass around the sender anyway so for me it works fine :)
Stephen Riley
@stephen-riley
The more I think about it, @me-slove, I just wasn't thinking hard enough about how TPL works vis-a-vis the different threads your Task<T> might continue on, and how Akka won't know anything about that. Completely different runtime contexts.
I'm gonna have to think a lot more about this and how I would want this to work ideally so I had something like ContinueWith() that was Akka-aware. Anyway, thanks for the thoughts.
Aaron Stannard
@Aaronontheweb
@stephen-riley we resolve Context by checking a thread-local variable
the value of Context is therefore, volatile
on top of that, the Context can change each time an actor processes a message
so it's a good practice to close over things like Sender and Self when you want to use them in continuations
Stephen Riley
@stephen-riley
heh, glad you confirmed that for me, @Aaronontheweb , as looking into the thread-local storage aspect of it was next on my list. :smiley: This is quite fun digging into this all!
Aaron Stannard
@Aaronontheweb
no problem
normally none of that stuff is an issue when you're working inside an actor
but yeah, when you want to re-use some of that state asynchronously
Stephen Riley
@stephen-riley
This really all started from "why do I need to explicitly specify a sender in Tell() while inside a continuation?" Been quite a lot of fun digging in.
Aaron Stannard
@Aaronontheweb
ah yeah
because our extension method that automatically supplies Self doesn't work outside the ActorCell
Context is basically the public API of the ActorCell
Stephen Riley
@stephen-riley
I know I could/should use PipeTo() for what I'm doing to be a little more "proper" about things, but you know how it is: once you start pulling a thread, you gotta see what unravels. :smile:
Aaron Stannard
@Aaronontheweb
I know how that feels