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

Bug: live queries kill DB connection #3978

Closed
2 tasks done
schronck opened this issue May 2, 2024 · 4 comments
Closed
2 tasks done

Bug: live queries kill DB connection #3978

schronck opened this issue May 2, 2024 · 4 comments
Assignees
Labels
bug Something isn't working question Further information is requested topic:live This is related to live queries and push notifications

Comments

@schronck
Copy link

schronck commented May 2, 2024

Describe the bug

If multiple programs try to subscribe for a live select the DB won't accept new connections after some time. We ran into this error while implementing a frontend in TypeScript (using surrealdb.js) where the UI started & stopped multiple SELECT LIVE statements. We also encountered this bug by the following code (which was specifically written to reproduce the bug).

Steps to reproduce

Steps:

  1. Start SurrealDB
  2. Compile and run the following program
  3. Run a separate program that writes into the specific table periodically

Program:

Dependencies

futures = { version = "0.3.29" }
serde = { version = "1.0.193", features = ["derive"] }
serde_json = { version = "1.0.108", features = [
    "float_roundtrip",
    "preserve_order",
] }
surrealdb = { version = "1.1.0" }
tokio = { version = "1.34.0", features = [
    "net",
    "time",
    "macros",
    "sync",
    "rt",
    "rt-multi-thread",
    "bytes",
] }
tracing = { version = "0.1.40" }
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
use std::{borrow::Cow, error::Error as StdError};

use clap::Parser;
use futures::StreamExt;
use serde::Deserialize;
use surrealdb::{
    engine::remote::ws::{Client, Ws},
    opt::auth::Root,
    sql::Thing,
    Notification, Surreal,
};
use tokio::sync::mpsc::{UnboundedReceiver, UnboundedSender};
use tracing::{error, info, instrument};
use tracing_subscriber::EnvFilter;

type Res<T, E = Box<dyn StdError + Send + Sync>> = Result<T, E>;
type SurrealClient = Surreal<Client>;

#[derive(Parser)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
    /// Connection to the database
    #[arg(short, long, env)]
    pub surreal_url: Cow<'static, str>,
}

enum Auth {
    User,
    Guest,
}

async fn connect_db(db_url: &str, auth: Auth) -> Res<SurrealClient> {
    let db = Surreal::new::<Ws>(db_url).await?;

    info!("Connected to database at {db_url}");

    if let Auth::User = auth {
        db.signin(Root {
            username: "test",
            password: "testpass",
        })
        .await?;
        info!("Successfully logged in to the database");
    } else {
        info!("Using a guest connection");
    }

    db.use_ns("testns").use_db("testdb").await?;

    Ok(db)
}

#[derive(Debug, Deserialize)]
struct Data {
    field1: String,
    field2: String,
}

#[derive(Debug, Deserialize)]
struct Test {
    id: Thing,
    data: Data,
}

#[instrument(skip_all, name = "faster")]
async fn faster(db: SurrealClient, tx: UnboundedSender<()>) -> Res<()> {
    let mut stream = db.select::<Vec<Test>>("test").live().await?;
    let mut index = 0;
    while let Some(noti_res) = stream.next().await {
        let Notification { action, data, .. } = noti_res?;
        info!(name = "data", ?action, field1 = %data.data.field1, field2 = %data.data.field2);
        index += 1;
        if index % 10 == 0 {
            info!("nudging slower");
            tx.send(())?;
        }
    }
    Ok(())
}

#[instrument(skip_all, name = "slower")]
async fn slower(db: SurrealClient, mut rx: UnboundedReceiver<()>) -> Res<()> {
    let mut stream = db.select::<Vec<Test>>("test").live().await?;
    while (rx.recv().await).is_some() {
        match stream.next().await {
            Some(Ok(Notification { action, data, .. })) => {
                        info!(name = "data", ?action, field1 = %data.data.field1, field2 = %data.data.field2);
            }
            Some(Err(e)) => {
                error!(name = "data error", ?e);
            }
            None => {
                error!("stream ended");
                return Ok(());
            }
        }
    }
    Ok(())
}

#[tokio::main]
async fn main() -> Res<()> {
    tracing_subscriber::fmt()
        .with_env_filter(EnvFilter::try_from_default_env()?)
        .init();

    let args = Cli::parse();

    let db_url = args.surreal_url;
    let db1 = connect_db(&db_url, Auth::User).await?;
    let db2 = connect_db(&db_url, Auth::Guest).await?;
    let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
    let jh1 = tokio::spawn(faster(db1, tx));
    let jh2 = tokio::spawn(slower(db2, rx));
    let (res1, res2) = tokio::join!(jh1, jh2);
    res1??;
    res2??;
    Ok(())
}

Expected behaviour

After a while (it can take as much as one day with this example) you shouldn't be able to create a new DB connection

SurrealDB version

surreal 1.4.2 for macOS on aarch64

Contact Details

No response

Is there an existing issue for this?

  • I have searched the existing issues

Code of Conduct

  • I agree to follow this project's Code of Conduct
@schronck schronck added bug Something isn't working triage This issue is new labels May 2, 2024
@phughk phughk self-assigned this May 2, 2024
@phughk
Copy link
Contributor

phughk commented May 2, 2024

This may be related to #3906

@phughk phughk added topic:live This is related to live queries and push notifications question Further information is requested and removed triage This issue is new labels May 13, 2024
@phughk
Copy link
Contributor

phughk commented May 13, 2024

Hi @schronck , can you confirm if this is resolved now? You can use the current version with --tick-interval 10s or upgrade to 1.5.0-beta1.

@schronck
Copy link
Author

@phughk thank you for the info. It seems like it works perfectly. I started all of containers appr. 15 minutes ago. It usually dropped the connections after few minutes. I will keep it running on my machine for a day and I will let you know if anything changed.

@schronck
Copy link
Author

schronck commented May 14, 2024

@phughk It's been running for almost a day now, and there were no errors, and haven't encountered our favorite bug sice the update. Thanks again!

@phughk phughk closed this as completed May 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working question Further information is requested topic:live This is related to live queries and push notifications
Projects
None yet
Development

No branches or pull requests

2 participants