Client-side Timestamps

Cassandra 2.1 introduced client-side timestamps. Client-side timestamps can be used to provide Cassandra with a client-side timestamp for database operations, rather than have it generated server-side. When this is enabled, it helps to mitigate Cassandra cluster clock skew, but may introduce application cluster clock skew as the client timestamp is used.

since cassadra v2.1

Using client-side timestamps

Given
a running cassandra cluster with schema:
  CREATE KEYSPACE simplex WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 3};
  CREATE TABLE simplex.users (
    user_id BIGINT PRIMARY KEY,
    first VARCHAR,
    last VARCHAR,
    age INT
  );
And
the following example:
  require 'cassandra'
  require 'delorean'

  # Enable client-side timestamps. Valid values:
  # nil / false : don't enable client-side timestamps. This is the default.
  # true : enable client-side timestamps and use the default timestamp generator for the Ruby flavor being used:
  #     JRuby - Cassandra::TimestampGenerator::TickingOnDuplicate
  #     MRI/Rubinius - Cassandra::TimestampGenerator::Simple
  # :simple : enable client-side timestamps and use a Cassandra::TimestampGenerator::Simple generator.
  # :monotonic : enable client-side timestamps and use a Cassandra::TimestampGenerator::TickingOnDuplicate generator.

  cluster = Cassandra.cluster(client_timestamps: :simple)
  session = cluster.connect("simplex")

  # Insert in the present
  session.execute("INSERT INTO users (user_id, first, last, age) VALUES (0, 'John', 'Doe', 40)", consistency: :all)

  # Set current time to the past, old client-side timestamp won't update the row
  Delorean.time_travel_to "1 minute ago" do
    # Simple statements
    session.execute("INSERT INTO users (user_id, first, last, age) VALUES (0, 'Mary', 'Holler', 22)", consistency: :all)
    row = session.execute("SELECT * FROM users WHERE user_id = 0").first
    puts "#{row["first"]} #{row["last"]} / #{row["age"]}"

    # Prepared statements
    insert = session.prepare("INSERT INTO users (user_id, first, last, age) VALUES (?, ?, ?, ?)")
    session.execute(insert, arguments: [0, 'Jane', 'Smith', 30], consistency: :all)
    row = session.execute("SELECT * FROM users WHERE user_id = 0").first
    puts "#{row["first"]} #{row["last"]} / #{row["age"]}"

    # Batch statements
    batch = session.batch do |b|
      b.add(insert, arguments: [0, 'Ruby', 'Driver', 2])
    end
    session.execute(batch, consistency: :all)
    row = session.execute("SELECT * FROM users WHERE user_id = 0").first
    puts "#{row["first"]} #{row["last"]} / #{row["age"]}"
  end
When
it is executed
Then
its output should contain:
John Doe / 40
John Doe / 40
John Doe / 40