Skip to content

Conversation

@jsonbailey
Copy link
Contributor

@jsonbailey jsonbailey commented Oct 21, 2025

In Android/iOS these action are run on the main thread whereas in netstandard they are run in a thread pool and are not guaranteed to be run in order when we don't wait for the result.


Note

Ensure scheduled actions run in order on netstandard by chaining them via a shared Task instead of using Task.Run.

  • Async scheduling (netstandard) in pkgs/sdk/client/src/PlatformSpecific/AsyncScheduler.netstandard.cs:
    • Introduce private static volatile Task _lastScheduledTask = Task.CompletedTask.
    • Replace Task.Run(a) with chaining: _lastScheduledTask = _lastScheduledTask.ContinueWith(_ => a()); to enforce ordered, fire-and-forget execution.

Written by Cursor Bugbot for commit e0169d4. This will update automatically on new commits. Configure here.

In Android/iOS these action are run on the main thread whereas in netstandard they are run in a threadpool and are not guaranteed to be run in order when we don't wait for the result.
@jsonbailey jsonbailey requested a review from a team as a code owner October 21, 2025 22:40
cursor[bot]

This comment was marked as outdated.

try
{
// Wait for the task to complete to ensure that actions are executed in the correct order.
Task.Run(a).Wait();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need a timeout here? Or do we already not timeout, and require the application code return in a timely manner?

Copy link
Contributor

@tanderson-ld tanderson-ld Oct 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think any amount of wait violates the AsyncScheduler contract, no?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, this probably isn't good on the caller side of the equation. It still does feel like we need a thread specifically to wait for these tasks, or a pool of 1 that we just submit to.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a queue of tasks that get linked together as added and the next is dispatched as the previous finishes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that works as well, potentially very similar to the async queues we've implemented for the CSI spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated it to be a chained list of calls. The continueWith should still work even if an action throws an exception. This should allow us to keep the same contract but enforce the order.

@cursor
Copy link

cursor bot commented Oct 23, 2025

Bug: Non-Atomic Task Scheduling Causes Concurrency Issues

The read-modify-write operation on _lastScheduledTask in PlatformScheduleAction is not atomic. Concurrent calls can read the same task, create parallel continuations, and overwrite each other's assignments. This breaks the ordering guarantee, causing actions to run concurrently instead of sequentially, and potentially losing some from the chain.

Fix in Cursor Fix in Web

Task.Run(a);
// Chain the new action to run after the previous one completes
// This ensures actions run in order while maintaining fire-and-forget behavior
_lastScheduledTask = _lastScheduledTask.ContinueWith(_ => a());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Race Condition in Task Scheduler

There's a race condition in PlatformScheduleAction. Concurrent calls can cause _lastScheduledTask to be updated non-atomically, which breaks the intended sequential ordering of scheduled tasks. This means tasks may execute out of order or in parallel, as volatile doesn't ensure atomicity for read-modify-write operations.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants