public Task <ActiveRoutineInfo> ScheduleRoutineAsync( ExecuteRoutineIntent intent, CancellationToken ct) { #warning Need to send message first, then create routine record. var routineId = Interlocked.Increment(ref _dataStore.RoutineCounter); var routineRecord = new RoutineStateRecord { ETag = DateTime.UtcNow.Ticks.ToString("X16"), Id = routineId.ToString(), Completion = new TaskCompletionSource <string>(), Continuation = intent.Continuation == null ? null : _serializer.SerializeToString(intent.Continuation) }; lock (_dataStore.Routines) { _dataStore.Routines.Add(routineRecord.Id, routineRecord); } var transitionDescriptor = new TransitionDescriptor { Type = TransitionType.InvokeRoutine, ETag = routineRecord.ETag }; var routineDescriptor = new RoutineDescriptor { MethodId = intent.MethodId, IntentId = intent.Id, RoutineId = routineRecord.Id, ETag = routineRecord.ETag }; var message = new Message { //["IntentId"] = _serializer.Serialize(intent.Id), [nameof(TransitionDescriptor)] = _serializer.SerializeToString(transitionDescriptor), [nameof(ServiceId)] = _serializer.SerializeToString(intent.ServiceId), [nameof(RoutineDescriptor)] = _serializer.SerializeToString(routineDescriptor), ["Parameters"] = _serializer.SerializeToString(intent.Parameters) }; _dataStore.ScheduleMessage(message); var info = new ActiveRoutineInfo { RoutineId = routineRecord.Id }; return(Task.FromResult(info)); }
private async void RunMessageInBackground(Message message) { if (message.DeliverAt.HasValue && message.DeliverAt > DateTime.UtcNow) { await Task.Delay(message.DeliverAt.Value - DateTime.UtcNow); } else { await Task.Yield(); } var ct = CancellationToken.None; if (message.IsEvent) { var serviceId = Serializer.Deserialize <ServiceId>(message[nameof(ServiceId)]); var eventId = Serializer.Deserialize <EventId>(message[nameof(EventId)]); var eventDesc = new EventDescriptor { EventId = eventId, ServiceId = serviceId }; var subscribers = DataStore.GetEventSubscribers(eventDesc); foreach (var subscriber in subscribers) { var routineId = Interlocked.Increment(ref DataStore.RoutineCounter); var routineRecord = new RoutineStateRecord { ETag = DateTime.UtcNow.Ticks.ToString("X16"), Id = routineId.ToString(), Completion = new TaskCompletionSource <string>() }; lock (DataStore.Routines) { DataStore.Routines.Add(routineRecord.Id, routineRecord); } var transitionDescriptor = new TransitionDescriptor { Type = TransitionType.InvokeRoutine, ETag = routineRecord.ETag }; var routineDescriptor = new RoutineDescriptor { MethodId = subscriber.MethodId, IntentId = _numericIdGenerator.NewId(), RoutineId = routineRecord.Id, ETag = routineRecord.ETag }; var invokeRoutineMessage = new Message { //["IntentId"] = _serializer.Serialize(intent.Id), [nameof(TransitionDescriptor)] = Serializer.SerializeToString(transitionDescriptor), [nameof(ServiceId)] = Serializer.SerializeToString(subscriber.ServiceId), [nameof(RoutineDescriptor)] = Serializer.SerializeToString(routineDescriptor), ["Parameters"] = message["Parameters"] }; DataStore.ScheduleMessage(invokeRoutineMessage); } } else { for (; ;) { var carrier = new TransitionCarrier(this, message); carrier.Initialize(); //var transitionInfo = await data.GetTransitionDescriptorAsync(ct); //if (transitionInfo.Type == TransitionType.InvokeRoutine || // transitionInfo.Type == TransitionType.ContinueRoutine) //{ // var routineDescriptor = await data.GetRoutineDescriptorAsync(ct); // if (!string.IsNullOrEmpty(transitionInfo.ETag) && // transitionInfo.ETag != routineDescriptor.ETag) // { // // Ignore - stale duplicate message // return; // } //} try { await _transitionRunner.RunAsync(carrier, ct); break; } catch (ConcurrentRoutineExecutionException) { // re-try continue; } } } }