AlexPikalov / cdrs

Cassandra DB native client written in Rust language. Find 1.x versions on https://github.com/AlexPikalov/cdrs/tree/v.1.x Looking for an async version? - Check WIP https://github.com/AlexPikalov/cdrs-async
Apache License 2.0
341 stars 58 forks source link

No prepared statement with ID {} found. #318

Closed ghost closed 3 years ago

ghost commented 4 years ago

Hi! Get this error when trying to update a CF multiple times in Scylla. I filed an issued to scylla and attached a tcpdump showing the traffic between the driver and the database. The Scylla team said it's a problem with the driver that's ignoring the error coming from Scylla (seems there's a cache for prepared statements and from time to time it gets evicted) instead of retrying to reprepare the statement.

AlexPikalov commented 4 years ago

Hi @bruno-barin-ifood , Can you please provide me with a code snipped that reproduces this behaviour?

ghost commented 4 years ago

Sure, here you are:


use cdrs::frame::Frame;
use cdrs::query::*;
use cdrs::types::prelude::*;
use log::error;
use rdkafka::consumer::Consumer;
use rdkafka::Message;

use model::Cart;
use settings::*;

mod model;
mod settings;

fn main() {
    env_logger::init();
    consume_messages();
}

const UPDATE_QUERY: &str = "UPDATE cart.carts SET cart = ?, status = ? WHERE id = ?";

struct Scylla {
    prepared_query: PreparedQuery,
    scylla_session: ScyllaSession
}

impl Scylla {
    fn new() -> Self {
        let prepared_query = self.scylla_session.prepare(UPDATE_QUERY).unwrap();
        let scylla_session = get_scylla_session();
        Scylla {
            prepared_query,
            scylla_session
        }
    }
    fn update_scylla(&self, cart: &Cart) -> Result<Frame> {

        self.scylla_session.exec_with_values(&self.prepared_query, cart.into_query_values())
    }
}

fn consume_messages() {
    let kafka_consumer = kafka_consumer();
    let scylla = Scylla::new();

    for potential_message in kafka_consumer.iter() {
        match potential_message {
            Err(e) => error!("Error to fetch message from Kafka. Reason: {}", e),
            Ok(message) => {
                let body = message.payload_view().unwrap().unwrap();
                let cart: Cart = serde_json::from_str(body).unwrap();
                let result = scylla.update_scylla(&cart);
                match result {
                    Ok(_) => {
                        kafka_consumer.store_offset(&message)
                            .expect("Failed to commit message to Kafka");
                    }
                    Err(_err) => println!("Cart {} failed due to connection problems - {}", cart.id, _err)
                }
            }
        }
    }
}

The link for the issue I've opened to the Scylla team is this one:

https://github.com/scylladb/scylla/issues/5936

AlexPikalov commented 4 years ago

@bruno-barin-ifood If you have a cluster with more than one Scylla/Cassandra nodes it may be problematic to execute prepared queries with current CDRS implementation - during the next request to cluster next or random node (depending on the balancing strategy) will be used so it may lead to the situation when such not doesn't have a corresponded prepared query registered. So it that regards CDRS may need some improvements

ghost commented 4 years ago

thanks @AlexPikalov !

slivne commented 4 years ago

Please note this can happen also in a single node, that is a Cassandra/Scylla node may invalidate the prepared statements (due to some internal reasons).

When a prepared statement will be executed the error of not having the prepared statement will be returned (https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L1169)

Most drivers at this point reprepare the statement and following that reexecute it.

So while it would be preferable to prepare a statement on all connections (to make sure its avail) yet this is not a must, it would be sufficient to handle the error and reexecute the statement.

AlexPikalov commented 4 years ago

@bruno-barin-ifood I've just read the conversation inside the issue that you've created for Scylla.

@slivne Got you. It's an interesting fact which was not known to me before.

I think I need to think how to make the driver smarter in that regards.

fggarcia commented 4 years ago

Hi @AlexPikalov do you have any progress with this issue?

is it possible to add a specific error for this?

except commented 4 years ago

I guess a work around for now is to just query directly with the prepared statement.