Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Background task #365

Closed
dalance opened this issue Jan 24, 2023 · 4 comments
Closed

Background task #365

dalance opened this issue Jan 24, 2023 · 4 comments
Labels
question Further information is requested

Comments

@dalance
Copy link
Contributor

dalance commented Jan 24, 2023

I want to implement background task like symbol table construction of the entire project directory.
If I call the task in callback (ex. did_changed), the next callback can't be processed until finishing the task.
Using spawn may resolve the problem, but communication between threads is not easy. So I prefer single thread.
Is there a proper way?

I think the following interface may be useful, for example.

#[tower_lsp::async_trait]
impl LanguageServer for Backend {
    async fn background(&self) -> Result<()> { // `background` is called at the time of no request.
        // small task which doesn't degrade response
    }
}
@ratmice
Copy link

ratmice commented Jan 24, 2023

I'm not sure spawn/communication between threads is really that bad, if nothing else i'd posted an example of that in #340 as I hadn't had any luck in using the tokio's LocalSet, to get thread local futures working, one thing that really helps is that Client is clone. Perhaps there is a better way, but it does work at a last resort

@ebkalderon
Copy link
Owner

Perhaps the symbol table data structure could be wrapped in an Arc<tokio::sync::RwLock<_>>, and this could be used to synchronize the background task?

async fn background(&self) -> Result<()> {
    // Wait for background task to complete, if any. If none, this
    // should resolve immediately.
    let _ = self.symbol_table.read().await;

    // Spawn background task...
    let mut symbol_table = self.symbol_table.clone();
    tokio::spawn(async move {
        let mut table = symbol_table.write().await;
        // Update `table` here. Next call to `background()` will only be
        // allowed to execute until after this guard is dropped.
    });

    // ...
}

FYI @ratmice, I hope to relax the Send bound requirements on LanguageServer futures eventually as part of #284 (comment), thereby supporting thread-local futures out of the box. The Client type will remain Send, of course, in case anyone wants to pass it into a Send task.

@dalance
Copy link
Contributor Author

dalance commented Jan 24, 2023

Thank you for your suggestion.
I'll try to use background thread.

@dalance dalance closed this as completed Jan 24, 2023
@ebkalderon
Copy link
Owner

Sure thing, @dalance! Feel free to post back with the results and if the behavior matches what you expect, and feel free to reopen the ticket if it doesn't resolve the issue. We can always iterate on ways to improve the experience going forward.

@ebkalderon ebkalderon added the question Further information is requested label Jan 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

3 participants