Exceptions because the provider can't deserialize datetimes.
ErroneousFatality opened this issue · 8 comments
I'm using the latest version of this library from Nuget, v2.4: https://www.nuget.org/packages/Orleans.Providers.MongoDB/
How can I deserialize DateTimes properly?
What exception do you get?
Exception:
fail: Orleans.Runtime.ReminderService.LocalReminderService[102915]
Could not deliver reminder tick for [RoundGrain_WakeMeUpInside, GrainReference:*grn/4D69D0BD/400625bf15bb63a8c712e9b338fbb18b030000004d69d0bd-0x53CDE135, 00:01:00, 2019-06-24 17:44:17.856 GMT, 5058680b-a0e4-4da1-9cfd-93dfa509d7e4, 36, Ticking], next 25.06.2019. 13.47.17.
Orleans.Runtime.OrleansException: Error from storage provider MongoGrainStorage.Grains.RoundGrain during ReadState for grain Type=Grains.RoundGrain Pk=*grn/4D69D0BD/400625bf15bb63a8c712e9b338fbb18b030000004d69d0bd-0x53CDE135 Id=GrainReference:*grn/4D69D0BD/38fbb18b Error=
Exc level 0: Newtonsoft.Json.JsonReaderException: Could not convert string to DateTime: 2019-06-24T19.43.17+02:00. Path 'RoundCreationTime'.
at Newtonsoft.Json.JsonReader.ReadDateTimeString(String s)
at Newtonsoft.Json.JsonReader.ReadAsDateTime()
at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Populate(JsonReader reader, Object target)
at Newtonsoft.Json.JsonSerializer.PopulateInternal(JsonReader reader, Object target)
at Orleans.Providers.MongoDB.StorageProviders.Serializers.JsonGrainStateSerializer.Deserialize(IGrainState grainState, JObject entityData)
at Orleans.Providers.MongoDB.StorageProviders.MongoGrainStorage.<>c__DisplayClass16_0.<<ReadStateAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Orleans.Providers.MongoDB.StorageProviders.MongoGrainStorage.<>c__DisplayClass20_0.<<DoAndLog>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Orleans.Providers.MongoDB.StorageProviders.MongoGrainStorage.DoAndLog[T](String actionName, Func`1 action)
at Orleans.Core.StateStorageBridge`1.ReadStateAsync() in D:\build\agent\_work\7\s\src\Orleans.Runtime\Storage\StateStorageBridge.cs:line 68 ---> Newtonsoft.Json.JsonReaderException: Could not convert string to DateTime: 2019-06-24T19.43.17+02:00. Path 'RoundCreationTime'.
at Newtonsoft.Json.JsonReader.ReadDateTimeString(String s)
at Newtonsoft.Json.JsonReader.ReadAsDateTime()
at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Populate(JsonReader reader, Object target)
at Newtonsoft.Json.JsonSerializer.PopulateInternal(JsonReader reader, Object target)
at Orleans.Providers.MongoDB.StorageProviders.Serializers.JsonGrainStateSerializer.Deserialize(IGrainState grainState, JObject entityData)
at Orleans.Providers.MongoDB.StorageProviders.MongoGrainStorage.<>c__DisplayClass16_0.<<ReadStateAsync>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Orleans.Providers.MongoDB.StorageProviders.MongoGrainStorage.<>c__DisplayClass20_0.<<DoAndLog>b__0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Orleans.Providers.MongoDB.StorageProviders.MongoGrainStorage.DoAndLog[T](String actionName, Func`1 action)
at Orleans.Core.StateStorageBridge`1.ReadStateAsync() in D:\build\agent\_work\7\s\src\Orleans.Runtime\Storage\StateStorageBridge.cs:line 68
--- End of inner exception stack trace ---
at Orleans.Core.StateStorageBridge`1.ReadStateAsync() in D:\build\agent\_work\7\s\src\Orleans.Runtime\Storage\StateStorageBridge.cs:line 80
at Orleans.LifecycleSubject.WrapExecution(CancellationToken ct, Func`2 action) in D:\build\agent\_work\7\s\src\Orleans.Core\Lifecycle\LifecycleSubject.cs:line 115
at Orleans.LifecycleSubject.OnStart(CancellationToken ct) in D:\build\agent\_work\7\s\src\Orleans.Core\Lifecycle\LifecycleSubject.cs:line 55
at Orleans.Runtime.Catalog.CallGrainActivate(ActivationData activation, Dictionary`2 requestContextData) in D:\build\agent\_work\7\s\src\Orleans.Runtime\Catalog\Catalog.cs:line 1170
at Orleans.Runtime.Scheduler.AsyncClosureWorkItem.Execute() in D:\build\agent\_work\7\s\src\Orleans.Runtime\Scheduler\ClosureWorkItem.cs:line 63
at Orleans.Runtime.Catalog.InitActivation(ActivationData activation, String grainType, String genericArguments, Dictionary`2 requestContextData) in D:\build\agent\_work\7\s\src\Orleans.Runtime\Catalog\Catalog.cs:line 556
at Orleans.Runtime.ReminderService.LocalReminderService.LocalReminderData.OnTimerTick(AverageTimeSpanStatistic tardinessStat, ILogger Logger) in D:\build\agent\_work\7\s\src\Orleans.Runtime\ReminderService\LocalReminderService.cs:line 583
State class:
public class RoundState
{
public IGameStrategy GameStrategy { get; set; }
public RoundStatus Status { get; set; }
public ICollection<ISlipGrain> RoundSlips { get; set; }
public ICollection<int> RoundNumbers { get; set; }
public DateTime RoundCreationTime { get; set; }
public DateTime SubmissionsEndTime { get; set; }
public DateTime NumbersGenerationTime { get; set; }
public DateTime FinalizationTime { get; set; }
public Guid GameStreamId { get; set; }
}
Are you trying to use reminders? What is your setup?
Yes I am using reminders.
I'm not sure which setup you are refering to.
In the example have a look at INewsReminderGrain
and confirm you are doing something similar.
Yeah, my RoundGrains (max 20 active at a time) register a Reminder on a 1minute interval to reactivate them, in case they get deactivated, because they have some Timer logic that needs to be done in their 20min lifecycle.
@SebastianStehle Any thoughts, please? I am not that accustomed to reminders.
We ran into DateTime serialization/deserialization problem as well. The culprit in our case seems to be MongoGrainStorage.ToBson (public static BsonValue ToBson(this JToken source)
)
The case for datetime looks like this:
case JTokenType.Date:
object obj = ((JValue) source).Value;
switch (obj)
{
case DateTime dateTime:
return (BsonValue) dateTime.ToString("yyyy-MM-ddTHH:mm:ssK");
case DateTimeOffset dateTimeOffset:
return (BsonValue) dateTimeOffset.UtcDateTime.ToString("yyyy-MM-ddTHH:mm:ssK");
default:
return (BsonValue) obj.ToString();
}
The ToString calls do not specify the format provider therefore the time separator (:) will get replaced by the current culture's DateTimeFormatInfo.TimeSeparator
. This cannot be configured even though the silo host builder configuration extension method would suggest this to be the case:
.AddMongoDBGrainStorage("YourStoreName", options =>
{
options.ConfigureJsonSerializerSettings = settings => settings.Culture = CultureInfo.InvariantCulture;
options.DatabaseName = "YourDatabaseName";
options.CollectionPrefix = "YourPrefgix";
})
Setting the culture has no effect on serializing DateTime values.