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

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

No prepared statement with ID {} found.

opened this issue · comments

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.

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

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:

scylladb/scylladb#5936

@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

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.

@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.

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

is it possible to add a specific error for this?

commented

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