-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RegisterAsStreamProducer failed: fullkey
field of StreamId
is null
#9224
Comments
Okay, apparently the action is taking place here in the IList<IBatchContainer> multiBatch = await rcvr.GetQueueMessagesAsync(maxCacheAddCount); // <---------------------------------
if (multiBatch == null || multiBatch.Count == 0) return false; // queue is empty. Exit the loop. Will attempt again in the next timer callback.
queueCache?.AddToCache(multiBatch);
numMessages += multiBatch.Count;
StreamInstruments.PersistentStreamReadMessages.Add(multiBatch.Count);
if (logger.IsEnabled(LogLevel.Trace))
logger.LogTrace(
(int)ErrorCode.PersistentStreamPullingAgent_11,
"Got {ReceivedCount} messages from queue {Queue}. So far {MessageCount} messages from this queue.",
multiBatch.Count,
myQueueId.ToStringWithHashCode(),
numMessages);
foreach (var group in
multiBatch
.Where(m => m != null)
.GroupBy(container => container.StreamId))
{
var streamId = new QualifiedStreamId(queueAdapter.Name, group.Key); // <---------------------------------
StreamSequenceToken startToken = group.First().SequenceToken;
StreamConsumerCollection streamData;
if (pubSubCache.TryGetValue(streamId, out streamData))
{
streamData.RefreshActivity(now);
StartInactiveCursors(streamData, startToken);
}
else
{
// And finally the call to RegisterAsStreamProducer is below
RegisterStream(streamId, startToken, now).Ignore(); // if this is a new stream register as producer of stream in pub sub system**
}
}
return true;
} I think my brain got so melted eliminating possible root causes, that I lacked the freshness of mind required to simply walk up the method call tree in the source code 😅 This gives me some pointers. |
Okay i got it solved, it turned out I stumbled on very nasty situation specific to F#. Regarding the null StreamId, the problem was these lines: [<Id(1u)>]
member val StreamId = streamId with get, set
[<Id(2u)>]
member val Events = events with get, set
....
interface IBatchContainer with
member this.StreamId = streamId When debugging using logs, I noticed that the Events property is actually correctly populated when accessed from outside the object (before that I was logging from within the object), which gave me the decisive clue. Unlike C#, in F# the parameters of the primary constructors are accessible across the whole class, they are not just scoped to the constructor function. In practice, this is a nice convenience made possible by the fact that everything is immutable by default in F#. But this is also what screwed me here. I have indeed realized that Orleans' native serializer does not use any constructor. As a result I was binding the IBatchContainer.StreamId to an empty value (namely The problem with the empty interface IBatchContainer with
member this.GetEvents<'T>() =
this.Events
|> Seq.filter (fun x -> x :? 'T)
|> Seq.map (fun x -> x :?> 'T)
|> Seq.mapi (fun i e ->
Tuple.Create<'T, StreamSequenceToken>(e, sequenceToken.CreateSequenceTokenForEvent(i))) For some reason, the [<Id(0u)>]
let mutable sequenceToken: EventSequenceToken = null I solved the problem by turning the field into a public property, but this looks like a bug to me. Serialization matters here since the batchContainer is passed across grain method calls. So all in all there were a bunch of serialization issues in different places for different reasons, and untangling what was going on hasn't been a fun experience at all. |
This might be an issue with the compiler using "ref assemblies", which strip private metadata before the source generator sees the assembly. There is very little which Orleans can do about that. You might be able to set |
I have implemented a custom PersistentStreamProvider by following the example of the Azure Queue Provider, and while the core logic seems to be working fine, I am getting the following exception:
Apparently the
fullkey
field ofStreamId
is null, while it is supposed to be serialized by the native serializer.This exception occurs just after
IList<IBatchContainer> IQueueAdapterReceiver.GetQueueMessagesAsync(maxCount)
returns the list ofIBatchContainers
. As a result none of the consumers receive any message and the rest of the pipeline is not executed (IQueueAdapterReceiver.MessagesDeliveredAsync(messages)
is not called etc...).I have verified that the messages batches are correctly serialized and deserialized. Upon deserialization their content looks like
StreamId:SERVERS_STREAM/ef3fc375fd2b490e96c20859d23a24fb,Context:,SequenceToken:[EventSequenceToken: SeqNum=3, EventIndex=0]
So the StreamId is at least set on the batch, however what has caught my attention is that the Events list is
null
upon deserialization. It is not even empty, it is null. And I have confirmed that it does contain events when it is serialized. Here is the IBatchContainer implementation (in f#):And here is the generated code, which looks fine to me:
I serialize the messages using
Orleans.Serialization.Serializer.SerializeToArray(batchMessage)
, and I have confirmed that the new native serializer is being used (ie. the one relying on theGenerateSerializer
attributes)What is particularly painful to me is that since
RegisterAsStreamProducer
is invoked by the Orleans framework, I have no idea where it gets the StreamId from, and therefore where the source of the issue could be. My guess is that the problem with the empty events should be unrelated since events do not even contain a StreamId, but this is not very helpful.And with the problem with slow debugging that will only be fixed in .NET 9, inspecting external code during a debugging session is essentially impossible (exceptions all over the place due to timeouts, debug symbols not loaded etc...).
Any pointer from someone familiar with the inner working of streams would be greatly appreciated. Just an educated guess on the root cause of the RegisterAsStreamProducer failed would already be massively helpful.
But since I do not even know where
Orleans.Streams.PersistentStreamPullingAgent.PubsubRegisterProducer(IStreamPubSub pubSub, QualifiedStreamId streamId, GrainId meAsStreamProducer, ILogger logger)
gets this streamId, investigating has been a very painful experience, I've been on it for close to 2 days already.The text was updated successfully, but these errors were encountered: