-
Notifications
You must be signed in to change notification settings - Fork 1
Samples
public class WorkflowContext: EternityContext {
public WorkflowContext(IServiceProvider services):
base(new EternityAzureStorage(("ET", "azure storage connection string...")), services, new EternityClock()) {
}
}
// register this as background service
public class WorkflowBackgroundService : BackgroundService {
private readonly WorkflowContext workflowContext;
private readonly TelemetryClient telemetryClient;
public WorkflowBackgroundService(WorkflowContext workflowContext, TelemetryClient telemetryClient)
{
this.workflowContext = workflowContext;
this.telemetryClient = telemetryClient;
}
protected async override Task ExecuteAsync(CancellationToken stoppingToken) {
while (!stoppingToken.IsCancellationRequested) {
try {
await workflowService.ProcessMessagesAsync(cancellationToken: stoppingToken);
} catch (Exception ex) {
telemetryClient.TrackException(ex);
}
}
}
}
To enable Microsoft.DependencyInjection.Extensions
Scope, add following in configure method.
services.AddEternityServiceScope();
This will make every activity execute in separate service scope, you can inject scoped services in Activities.
// create new workflow and execute now
var id = await SignupWorkflow.CreateAsync(context, "[email protected]");
// raise an event...
await context.RaiseEventAsync(id, SignupWorkflow.Verify, verificationCode);
Lets assume we want to verify email address of user before signup, we want to set max timeout to 45 minutes and maximum 3 retries.
Activities are methods of the same class marked with [Activity]
attribute and methods must be public and virtual.
Activities can also be scheduled in future by passing a parameter marked with [Schedule]
attribute as shown below.
public class SignupWorkflow : Workflow<SignupWorkflow, string, string> {
// name of external event
public const string Resend = nameof(Resend);
// name of external event
public const string Verify = nameof(Verify);
public override async Task<string> RunAsync(string input)
{
var maxWait = TimeSpan.FromMinutes(15);
var code = (this.CurrentUtc.Ticks & 0xF).ToString();
await SendEmailAsync(input, code);
for (int i = 0; i < 3; i++)
{
var (name, result) = await WaitForExternalEventsAsync(maxWait, Resend, Verify);
switch(name)
{
case Verify:
if(result == code)
{
return "Verified";
}
break;
case Resend:
await SendEmailAsync(input, code, i);
break;
}
}
return "NotVerified";
}
[Activity]
public virtual async Task<string> SendEmailAsync(
string emailAddress,
string code,
int attempt = -1,
[Inject] MockEmailService emailService = null) {
await Task.Delay(100);
emailService.Emails.Add((emailAddress, code, CurrentUtc));
return $"{emailService.Emails.Count-1}";
}
}
For mobile, on iOS, there is no way to generate the code, so you can use Schedule method by importing .Mobile
namespace as shown below.
var maxWait = TimeSpan.FromMinutes(15);
var code = (this.CurrentUtc.Ticks & 0xF).ToString();
await SendEmailAsync(input, code);
for (int i = 0; i < 3; i++)
{
var (name, result) = await WaitForExternalEventsAsync(maxWait, Resend, Verify);
switch(name)
{
case Verify:
if(result == code)
{
return "Verified";
}
break;
case Resend:
// note this will use method delegate and will ensure that we are passing
// same type of parameters, the only problem is you will have to supply all
// default parameters as well
await this.ScheduleAsync( SendEmailAsync, input, code, i, null);
break;
}
}
return "NotVerified";
In the following example, we are creating Renew Membership Workflow when user registers for one year.
public class RenewMembershipWorkflow: Workflow<RenewMembershipWorkflow,long,string> {
public async Task<string> RunAsync(long id) {
var at = TimeSpan.FromDays(364);
// at this time, this workflow will be suspended and removed from the execution
// internally it will throw `ActivitySuspendedException` and it will start
// just before the given timespan
for(int i = 0; i<3; i++) {
var success = await RewewAsync(id, at);
if(success) {
// restart the same workflow
await RenewMembershipWorkflow.CreateAsync(this.Context, id);
return "Done";
}
// try after 3 days again...
at = TimeSpan.FromDays(3);
}
// renewal failed...
return "Failed";
}
[Activity]
public virtual async Task<bool> RenewAsync(
long id,
[Schedule] TimeSpan at,
[Inject] IPaymentService paymentService = null,
[Inject] IEmailService emailService = null
) {
var result = await paymentService.ChargeAsync(id);
if(result.Success) {
return true;
}
await emailService.SendFailedRenewalAsync(id);
return false;
}
}