Skip to content

Document the cancellation behavior of LocalResource and AsyncDerived #4434

@zstewar1

Description

@zstewar1

Is your feature request related to a problem? Please describe.
When using LocalResource, it's not clear what the sequencing and cancellation behavior is. For example, what happens if one of the dependencies changes faster than the future completes? What if my async fetcher function has side effects?

For example:

async fn a_slow_fetch_operation(ms: u64) -> u64 {
    tokio::time::sleep(Duration::from_millis(ms));
    ms / 2
}

let some_signal = RwSignal::new(10_000);

let res = LocalResource::new(|| async {
    let some_value = a_slow_fetch_operation(some_signal.get()).await;
    store_in_local_storage(some_value);
});

some_signal.set(100);

Here, the second fetch will obviously complete before the first fetch. What I need to know is:

  1. What values will the LocalResource.get() take? Will it go straight from None to Some(50), or will the second fetch be delayed until the first one completes? Is there a risk of it going backwards from Some(50) to Some(5000)?
  2. What about the side-effects? Could the local-storage value transition from 50 to 5000?
    • Obviously there's no way for LocalResource to guarantee that intermediate side effects of the fetch operation don't get called, what I'm most concerned about is LocalResource making guarantees about stopping async processing of one request before starting the next; that is, guaranteeing that no new side-effects will happen after the next effect starts.

Describe the solution you'd like
I would like the documentation for LocalResource to give a clearer description of how it handles cancellation when signal dependencies change, and to explicitly specify any guarantees it makes about when it will start/stop processing one fetch call relative to other fetch calls.

Describe alternatives you've considered
If LocalResource makes guarantees about the state ordering of its .get() return value, but not about cancelling pending fetch functions, I guess I could use and Effect to handle side effects:

let res = LocalResource::new(|| async {
    a_slow_fetch_operation(some_signal.get()).await
});
Effect::new(move || {
    if  let Some(some_value) = res.get() {
        store_in_local_storage(some_value);
    }
});

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions