Async state
Async state stores progress and cancellation information for long running jobs. Entries live in the cache so Async state provides a lightweight shared store for long running jobs. It lets multiple servers exchange progress and cancellation information. For example, when an admin starts a product import, the import service could write its progress and a CancellationToken
to the distributed async state cache. Any request, even on another server, can read the entry to display a progress bar or cancel the job. An easy example can be found at the bottom of this page.
Create a state entry
Inject IAsyncState
and create an initial item. Attach a CancellationTokenSource
to allow external cancellation.
public record ImportState(int Progress);
public class ImportService
{
private readonly IAsyncState _state;
public ImportService(IAsyncState state) => _state = state;
public async Task RunAsync(CancellationToken token)
{
var cts = CancellationTokenSource.CreateLinkedTokenSource(token);
await _state.CreateAsync(new ImportState(0), "import", cancelTokenSource: cts);
}
}
Update and read progress
Use UpdateAsync
to mutate the stored object. Read it with GetAsync
. The key combines the type and an optional name.
await _state.UpdateAsync<ImportState>(s => s.Progress = 50, "import");
var state = await _state.GetAsync<ImportState>("import");
Cancel a process
Call Cancel
to request a stop. The stored token is cancelled.
_state.Cancel<ImportState>("import");
Expire and remove entries
Items expire after fifteen minutes of inactivity. Pass neverExpires: true
to keep them longer and always remove them when done.
await _state.RemoveAsync<ImportState>("import");
Expose progress to the client
This example shows how a product import exposes its progress to the client.
Server
[HttpPost]
public async Task<JsonResult> ProductImportProgress(int id)
{
var progress = await _asyncState.GetAsync<ProductImportState>(id.ToStringInvariant());
return Json(progress);
}
Client
$(function () {
$("#btn-start-product-import").on('click', (e) => {
// Start throbber and display notifications.
$.throbber.show({
message: `
<div id="import-message">@T("Plugins.Smartstore.ProductImport.Wait").Value</div>
<div id="import-progress" class="mt-2 mb-4"></div>`
});
window.setInterval(checkImportProgress, 1500);
return false;
});
function checkImportProgress() {
$.ajax({
cache: false,
type: 'POST',
url: '@Url.Action("ProductImportProgress", "Import", new { area = "Admin" })',
dataType: 'json',
data: $('#frm-product-import').serialize(),
success: function (data) {
if (data) {
$("#import-progress").html(data.ProgressMessage);
}
},
error: function (xhr, ajaxOptions, thrownError) { }
});
}
});
Last updated
Was this helpful?