Null reference when trying to get a grain from GrainFactory
- Dominant language
- C#
- Stars
- 10.9k
- Forks
- 2.1k
- Avg merge
- 14h 42m
- Merged PRs (30d)
- 354
Description
Hello there,
We have a KafkaConsumer and it is singleton.
```csharp
using KafkaFlow;
namespace ***.API.Infrastructure.Kafka.Consumers.Orders;
public class OrderConsumer(IClusterClient clusterClient, ILogger logger) : IMessageHandler
{
public async Task Handle(IMessageContext context, OrderIntegrationEvent message)
{
if (message is
{
OrderState: OrderState.Rejected or
OrderStateEnum.CanceledByAdmin or
OrderStateEnum.CanceledByCustomer or
OrderStateEnum.CanceledByNfc or
OrderStateEnum.CanceledBySystem
})
{
try
{
var customerGrain = clusterClient.GetGrain(message.Buyer.CustomerId);
var referenceId = message.Id.ToString();
await customerGrain.RequestToRefundAsync(new()
{
Amount = null,
CustomerId = message.Buyer.CustomerId,
ReferenceId = referenceId,
RefundReferenceId = referenceId,
Description = "From Kafka consumer"
});
}
catch (Exception ex)
{
logger.LogError(ex, "An exception has occurred in order consumer");
}
}
}
}
```
this is the code initial code, we get a reference to ICustomerGrain through clusterClient, and then the RequestToRefundAsync method in ICustomerGrain needs to resolve another grain.
The below method is in a Grain class.
```csharp
public async Task RequestToRefundAsync(RequestToRefund request)
{
try
{
await using var scope = this.ServiceProvider.CreateAsyncScope();
var paymentRequestService = scope.ServiceProvider.GetRequiredService();
var detail = await paymentRequestService.GetPaymentRequestDetails(request.ReferenceId);
var referenceIdGrain = this.GrainFactory.GetGrain(request.ReferenceId);
if (detail!.RefundedAmount < 1 && request.Amount.HasValue is false)
{
await referenceIdGrain.RequestToFullRefundAsync(new()
{
ReferenceId = request.ReferenceId,
RefundReferenceId = request.RefundReferenceId,
CustomerId = request.CustomerId,
Description = request.Description
});
}
else
{
await referenceIdGrain.RequestToPartialRefundAsync(new()
{
ReferenceId = request.ReferenceId,
RefundReferenceId = request.RefundReferenceId,
CustomerId = request.CustomerId,
Amount = request.Amount ?? (detail.TotalAmount - detail.RefundedAmount),
Description = request.Description
});
}
}
catch (Exception ex)
{
// metrics
throw;
}
}
```
but this line is the source of the problem, and we get null reference exception after calling ```referenceIdGrain```, the rate of this problem is high in this consumer, and we don't know why is that!
```csharp
var referenceIdGrain = this.GrainFactory.GetGrain(request.ReferenceId);
```
```
System.NullReferenceException: Object reference not set to an instance of an object.
at OPay.API.Grains.CustomerGrain.RequestToRefundAsync(RequestToRefund request) in /opay/src/OPay.API/Grains/CustomerGrain.cs:line 83
at OPay.API.Grains.CustomerGrain.RequestToRefundAsync(RequestToRefund request) in /opay/src/OPay.API/Grains/CustomerGrain.cs:line 107
at Orleans.Runtime.TaskRequest.CompleteInvokeAsync(Task resultTask) in /_/src/Orleans.Core.Abstractions/Runtime/GrainReference.cs:line 750
--- End of stack trace from previous location ---
at Orleans.Serialization.Invocation.ResponseCompletionSource.System.Threading.Tasks.Sources.IValueTaskSource.GetResult(Int16 token) in /_/src/Orleans.Serialization/Invocation/ResponseCompletionSource.cs:line 98
at System.Threading.Tasks.ValueTask.ValueTaskSourceAsTask.<>c.<.cctor>b__4_0(Object state)
--- End of stack trace from previous location ---
```
maybe this issue can help and be relatable:
https://github.com/dotnet/orleans/issues/5275
Contributor guide
Research direction
Start with the CustomerGrain.RequestToRefundAsync stack trace and CustomerGrain.cs lines 83 and 107, then compare the reported behavior with issue #5275. Reproduce the call path from the Kafka consumer through ICustomerGrain and record the Orleans version and complete exception details. Done means identifying the null object and documenting or fixing a reproducible cause.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- distributed-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100