I'm using ThreadPool.QueueUserWorkItem for do an async task that do POST request via HTTP.
ThreadPool.QueueUserWorkItem(new WaitCallback(UploadPhoto), photoFileName);
For now I want to add possibility for a canceling upload from UI.
I have two questions:
How can I realize thread interruption?
Is ThreadPool suitable for my target?
Consider using Task.Factory.StartNew to do async work on WP7. You can use CancellationTokens to force a cancellation. This is how I do my async work. To realize an interruption, you can do the following (using Tasks):
var task = Task.Factory.StartNew( ( )=>
{
// some operation that will be cancelled
return "some value";
})
.ContinueWith( result =>
{
if(result.Status == TaskStatus.Cancelled) // you have other options here too
{
// handle the cancel
}
else
{
string val = result.Result; // will be "some value";
}
});
The ContinueWith clause chains another method to occur after the body of the first task completes (one way or another). The parameter 'result' for the ContinueWith method is the Task that the ContinueWith is chained to, and there is a property called Result on the task 'result' that is whatever return value is supplied by the preceding task.
Related
I've implemented API data caching in my app so that if data is already present it is not re-fetched.
I can intercept the initial fetch
cy.intercept('**/api/things').as('api');
cy.visit('/things')
cy.wait('#api') // passes
To test the cache is working I'd like to explicitly test the opposite.
How can I modify the cy.wait() behavior similar to the way .should('not.exist') modifies cy.get() to allow the negative logic to pass?
// data is cached from first route, how do I assert no call occurs?
cy.visit('/things2')
cy.wait('#api')
.should('not.have.been.called') // fails with "no calls were made"
Minimal reproducible example
<body>
<script>
setTimeout(() =>
fetch('https://jsonplaceholder.typicode.com/todos/1')
}, 300)
</script>
</body>
Since we test a negative, it's useful to first make the test fail. Serve the above HTML and use it to confirm the test fails, then remove the fetch() and the test should pass.
The add-on package cypress-if can change default command behavior.
cy.get(selector)
.if('exist').log('exists')
.else().log('does.not.exist')
Assume your API calls are made within 1 second of the action that would trigger them - the cy.visit().
cy.visit('/things2')
cy.wait('#alias', {timeout:1100})
.if(result => {
expect(result.name).to.eq('CypressError') // confirm error was thrown
})
You will need to overwrite the cy.wait() command to check for chained .if() command.
Cypress.Commands.overwrite('wait', (waitFn, subject, selector, options) => {
// Standard behavior for numeric waits
if (typeof selector === 'number') {
return waitFn(subject, selector, options)
}
// Modified alias wait with following if()
if (cy.state('current').attributes.next?.attributes.name === 'if') {
return waitFn(subject, selector, options).then((pass) => pass, (fail) => fail)
}
// Standard alias wait
return waitFn(subject, selector, options)
})
As yet only cy.get() and cy.contains() are overwritten by default.
Custom Command for same logic
If the if() syntax doesn't feel right, the same logic can be used in a custom command
Cypress.Commands.add('maybeWaitAlias', (selector, options) => {
const waitFn = Cypress.Commands._commands.wait.fn
// waitFn returns a Promise
// which Cypress resolves to the `pass` or `fail` values
// depending on which callback is invoked
return waitFn(cy.currentSubject(), selector, options)
.then((pass) => pass, (fail) => fail)
// by returning the `pass` or `fail` value
// we are stopping the "normal" test failure mechanism
// and allowing downstream commands to deal with the outcome
})
cy.visit('/things2')
cy.maybeWaitAlias('#alias', {timeout:1000})
.should(result => {
expect(result.name).to.eq('CypressError') // confirm error was thrown
})
I also tried cy.spy() but with a hard cy.wait() to avoid any latency in the app after the route change occurs.
const spy = cy.spy()
cy.intercept('**/api/things', spy)
cy.visit('/things2')
cy.wait(2000)
.then(() => expect(spy).not.to.have.been.called)
Running in a burn test of 100 iterations, this seems to be ok, but there is still a chance of flaky test with this approach, IMO.
A better way would be to poll the spy recursively:
const spy = cy.spy()
cy.intercept('**/api/things', spy)
cy.visit('/things2')
const waitForSpy = (spy, options, start = Date.now()) => {
const {timeout, interval = 30} = options;
if (spy.callCount > 0) {
return cy.wrap(spy.lastCall)
}
if ((Date.now() - start) > timeout) {
return cy.wrap(null)
}
return cy.wait(interval, {log:false})
.then(() => waitForSpy(spy, {timeout, interval}, start))
}
waitForSpy(spy, {timeout:2000})
.should('eq', null)
A neat little trick I learned from Gleb's Network course.
You will want use cy.spy() with your intercept and use cy.get() on the alias to be able to check no calls were made.
// initial fetch
cy.intercept('**/api/things').as('api');
cy.visit('/things')
cy.wait('#api')
cy.intercept('METHOD', '**/api/things', cy.spy().as('apiNotCalled'))
// trigger the fetch again but will not send since data is cached
cy.get('#apiNotCalled').should('not.been.called')
In the diagram below from this page it shows that when an incomplete task is returned by the call to OnInitializedAsync it will await the task and then render the component.
However it seems that what actual happens when an incomplete task is returned is renders the component immediately, and then renders it again once the incomplete task completes.
An example later in the page seems to confirm this. If the component was not rendered immediately after the call to OnInitializedAsync, and instead only rendered for the first time after the Task returned had been completed you would never see the "Loading..." message.
OnParametersSetAsync behavior appears the same. It renders once immediately when an incomplete task is returned, and then again once that task has completed.
Am I misunderstanding the render lifecycle, or is this an error in the documentation?
Thanks
#page "/fetchdata"
#using BlazorSample.Data
#inject WeatherForecastService ForecastService
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from a service.</p>
#if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<!-- forecast data in table element content -->
</table>
}
#code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
}
}
To fully answer your question we need to delve into the ComponentBase code.
Your code is running in the async world where code blocks can yield and give control back to the caller - your "incomplete task is returned".
SetParametersAsync is called by the Renderer when the component first renders and then when any parameters have changed.
public virtual Task SetParametersAsync(ParameterView parameters)
{
parameters.SetParameterProperties(this);
if (!_initialized)
{
_initialized = true;
return RunInitAndSetParametersAsync();
}
else
return CallOnParametersSetAsync();
}
RunInitAndSetParametersAsync is responsible for initialization. I've left the MS coders' comments in which explains the StateHasChanged calls.
private async Task RunInitAndSetParametersAsync()
{
OnInitialized();
var task = OnInitializedAsync();
if (task.Status != TaskStatus.RanToCompletion && task.Status != TaskStatus.Canceled)
{
// Call state has changed here so that we render after the sync part of OnInitAsync has run
// and wait for it to finish before we continue. If no async work has been done yet, we want
// to defer calling StateHasChanged up until the first bit of async code happens or until
// the end. Additionally, we want to avoid calling StateHasChanged if no
// async work is to be performed.
StateHasChanged();
try
{
await task;
}
catch // avoiding exception filters for AOT runtime support
{
if (!task.IsCanceled)
throw;
}
// Don't call StateHasChanged here. CallOnParametersSetAsync should handle that for us.
}
await CallOnParametersSetAsync();
}
CallOnParametersSetAsync is called on every Parameter change.
private Task CallOnParametersSetAsync()
{
OnParametersSet();
var task = OnParametersSetAsync();
// If no async work is to be performed, i.e. the task has already ran to completion
// or was canceled by the time we got to inspect it, avoid going async and re-invoking
// StateHasChanged at the culmination of the async work.
var shouldAwaitTask = task.Status != TaskStatus.RanToCompletion &&
task.Status != TaskStatus.Canceled;
// We always call StateHasChanged here as we want to trigger a rerender after OnParametersSet and
// the synchronous part of OnParametersSetAsync has run.
StateHasChanged();
return shouldAwaitTask ?
CallStateHasChangedOnAsyncCompletion(task) :
Task.CompletedTask;
}
In the diagram substitute "Render" for StateHasChanged in the code above.
The diagram uses the work "Render", which is a bit misleading. It implies that the UI re-renders, when what actually happens is a render fragment (a block of code that builds the UI markup for the component) is queued on the Renderer's render queue. It should say "Request Render" or something similar.
If the component code that triggers a render event, or calls StateHasChanged, is all synchronous code, then the Renderer only gets thread time when the code completes. Code blocks need to "Yield" for the Renderer to get thread time during the process.
It's also important to understand that not all Task based methods yield. Many are just synchronous code in a Task wrapper.
So, if code in OnInitializedAsync or OnParametersSetAsync yields there's a render event on the first yield and then on completion.
A common practice to "yield" in a block of synchronous code is to add this line of code where you want the Renderer to render.
await Task.Delay(1);
You can see ComponentBase here - https://github.com/dotnet/aspnetcore/blob/main/src/Components/Components/src/ComponentBase.cs
Short summary
Blazor adds two 'free' StateHasChanged calls, before and after each lifecycle event and UI event.
StateHasChanged only requests an html update, it does not perform one.
An update request can only be fulfilled after the event
or when the main Thread is released by an await
not every await will release the Thread.
So, when you want to make sure the screen gets updated, use
StateHasChanged();
await Task.Delay(1);
Old answer
when an incomplete task is returned it renders the component immediately, and then renders it again once the incomplete task completes.
Yes, that is a possible sequence.
The flowchart shows the steps for showing a component. What is not so clear from the picture is that the actual rendering is not part of this flow, it happens async on the synchronizationcontext. It can happen when your code awaits something.
So we have this basis non-async sequence:
Oninitialzed[Async]
OnParametersSet[Async]
Render
OnAfterRender[Async]
But when there is something async in this code-path then there can be one extra Render during the await. More Renders are possible when you call StateHasChanged during this flow.
I am currently working on a project where I send UDP commands to a Tello drone.
The problem is that it uses UDP and when I send commands too fast before the previous one hasn't finished yet, the second command/action doesn't take place. I am using RxJS for this project and I want to create a mechanism to wait for the response ("ok" or "error") from the drone.
My Idea is to have 2 different observables. 1 observable that is the input stream from the responses from the drone and one observable of observables that I use as a commandQueue. This commandQueue has simple observables on it with 1 command I want to send. And I only want to send the next command when I received the "ok" message from the other observable. When I get the "ok" I would complete the simple command observable and it would automatically receive the next value on the commandQueue, being the next command.
My code works only when I send an array of commands, but I want to call the function multiple times, so sending them 1 by 1.
The following code is the function in question, testsubject is an observable to send the next command to the drone.
async send_command_with_return(msg) {
let parentobject = this;
let zeroTime = timestamp();
const now = () => numeral((timestamp() - zeroTime) / 10e3).format("0.0000");
const asyncTask = data =>
new Observable(obs => {
console.log(`${now()}: starting async task ${data}`);
parentobject.Client.pipe(take(1)).subscribe(
dataa => {
console.log("loool")
obs.next(data);
this.testSubject.next(data);
console.log(`${now()}: end of async task ${data}`);
obs.complete();
},
err => console.error("Observer got an error: " + err),
() => console.log("observer asynctask finished with " + data + "\n")
);
});
let p = this.commandQueue.pipe(concatMap(asyncTask)).toPromise(P); //commandQueue is a subject in the constructor
console.log("start filling queue with " + msg);
zeroTime = timestamp();
this.commandQueue.next(msg);
//["streamon", "streamoff", "height?", "temp?"].forEach(a => this.commandQueue.next(a));
await p;
// this.testSubject.next(msg);
}
streamon() {
this.send_command_with_return("streamon");
}
streamoff() {
this.send_command_with_return("streamoff");
}
get_speed() {
this.send_command_with_return("speed?");
}
get_battery() {
this.send_command_with_return("battery?");
}
}
let tello = new Tello();
tello.init();
tello.streamon();
tello.streamoff();
You can accomplish sending commands one at a time by using a simple subject to push commands through and those emissions through concatMap which will execute them one at a time.
Instead of trying to put all the logic in a single function, it will may be easier to make a simple class, maybe call it TelloService or something:
class TelloService {
private commandQueue$ = new Subject<Command>();
constructor(private telloClient: FakeTelloClient) {
this.commandQueue$
.pipe(
concatMap(command => this.telloClient.sendCommand(command))
)
.subscribe()
}
sendCommand(command: Command) {
this.commandQueue$.next(command);
}
}
When the service is instantiated, it subscribes to the commandQueue$ and for each command that is received, it will "do the work" of making your async call. concatMap is used to process commands one at a time.
Consumers would simply call service.sendCommand() to submit commands to the queue. Notice commands are submitted one at a time, it's not necessary to submit an array of commands.
Here is a working StackBlitz example.
To address your condition of waiting until you receive an ok or error response before continuing, you can use takeWhile(), this means it will not complete the observable until the condition is met.
To introduce a max wait time, you can use takeUntil() with timer() to end the stream if the timer emits:
this.commandQueue$
.pipe(
concatMap(command => this.telloClient.sendCommand(command).pipe(
takeWhile(status => !['ok', 'error'].includes(status), true),
takeUntil(timer(3000))
))
)
.subscribe()
Here's an updated StackBlitz.
In one documentation they say IHandleMessages handler hast to be written this way (signature is automatically generated when I choose to "Implement interface" option in Visual Studio):
public class PlaceOrderHandler : IHandleMessages<PlaceOrder>
{
public Task Handle(PlaceOrder message, IMessageHandlerContext context)
{
var orderPlaced = new OrderPlaced { OrderId = message.OrderId };
return context.Publish(orderPlaced);
}
}
While another documentation says it has to be written this way:
public class PlaceOrderHandler : IHandleMessages<PlaceOrder>
{
public async Task Handle(PlaceOrder message, IMessageHandlerContext context)
{
var orderPlaced = new OrderPlaced { OrderId = message.OrderId };
await context.Publish<OrderPlaced>(e => { e.OrderId = message.OrderId; });
}
}
I wonder what is the difference between these two statements, can someone explain in simple language?
Which option is the right one?
Both are correct options. The difference between the two is how a single asynchronous operation is handles in the Handle method.
In the first case, a Task is returned as-is. In the second case, publishing is awaited within the Handle method. The difference? In the first case no async state machine is created by the compiler as the task of publishing returned back. In the second scenario, a state machine is created.
Which option is the right one to use? They are both correct options. If a method is called frequently and you care for the unnecessary allocations not to take place, returnng a single task without awaiting is more efficient.
I have async method that returns Task. From time to time my process is recycling/restarting. Work is interruping in the middle of the Task. Is there more or less general approach in TPL that I can at least log that Task was interruped?
I am hosting in ASP.NET, so I can use IRegisteredObject to cancel tasks with CancellationToken. I do not like this however. I need to pass CancellationToken in all methods and I have many of them.
try..finally in each method does not seem even to raise. ContinueWith also does not work
Any advice?
I have single place I start my async tasks, however each task can have any number of child tasks. To get an idea:
class CommandRunner
{
public Task Execute(object cmd, Func<object, Task> handler)
{
return handler(cmd).ContinueWith(t =>
{
if (t.State = == TaskStatus.Faulted)
{
// Handle faultes, log them
}
else if (x.Status == TaskStatus.RanToCompletion)
{
// Audit
}
})
}
}
Tasks don't just get "interrupted" somehow. They always get completed, faulted or cancelled. There is no global hook to find out about those completions. So the only option to do your logging is to either instrument the bodies of your tasks or hook up continuations for everything.