Cassie provides ruby application support for Apache Cassandra. It provides components that most applications will need that are out of scope of the official cassandra-driver
, including:
- Database configuration
- Cluster/session management
- Cassandra server command helpers
- Versioned schema migrations
- Query classes and DSL
- Test harnessing
Each of these components are designed to be used independently or together in a ruby application. If you want to manage your own configuration, use Cassie for session management, and some other gem for your queries -- great!
Tested against:
- Ruby: MRI 2.2, 2.3, and JRuby 1.9
cassandra-driver
3.0
# Gemfile
gem 'cassie', '~> 1.1.0'
or
$ gem install cassie
See cassie-rails
for Rails integration.
Cassie provies database connection configuration (e.g. cluster and session) per environment. Support for a default YAML back-end is provided.
$ cassie configuration:generate
Cassie::configurations
are loaded from this configuration file at runtime.
Cassie.confurations
=> {"development"=>{"hosts"=>["127.0.0.1"], "port"=>9042, "keyspace"=>"my_app_development"}, "test"=>{"hosts"=>["127.0.0.1"], "port"=>9042, "idle_timeout"=>"nil", "keyspace"=>"my_app_test"}, "production"=>{"hosts"=>["cass1.my_app.biz", "cass2.my_app.biz", "cass3.my_app.biz"], "port"=>9042, "keyspace"=>"my_app_production"}}
Cassie.configurationpulls the appropriate configuration from
Cassie.configurations, based on
Cassie.env`.
Cassie.env = "production"
Cassie.configuration
{"hosts"=>["cass1.my_app.biz", "cass2.my_app.biz", "cass3.my_app.biz"], "port"=>9042, "keyspace"=>"my_app_production"}
Cassie.keyspace
=> 'my_app_production'
Cassie.env
prefers ENV["CASSANDRA_ENV"]
, then ENV["RACK_ENV"]
, and falls back to development
.
See the Configuration
README for more on features and usage.
Cassie provides cluster and session connection creation according to cassie-driver
best practices.
cluster
and session
objects are created, cached, and reused globally.
# continuing from above 'production' configuration
Cassie.cluster
=> #<Cassandra::Cluster:0x3fc032f7f9b8> #<= configured with production cluster `configuration` options
Cassie.session
=> #<Cassandra::Session:0x3fc084caa344> #<= session scoped to default 'my_app_production' keyspace
Cassie.session(nil)
=> #<Cassandra::Session:0x3fc084caba22> #<= session without scoped keyspace
Cassie.session('my_other_keyspace')
=> #<Cassandra::Session:0x3fc084cabf33> #<= session scoped to 'my_other_keyspace' keyspace
Cassie.session
=> #<Cassandra::Session:0x3fc084caa344> #<= cached session, scoped to default 'my_app_production' keyspace
If using Cassie Configuration as described above via cassandra.yml
, cluster configuration happens automatically. If not, assign a cluster environments hash to Cassie::configurations
before using a cluster
or session
.
Include Cassie::Connection
in a class for session
and keyspace
functionality in your objects.
class MyQuery
include Cassie::Connection
# An explicit keyspace that will determine the session used
# instead of falling back to the value in `Cassie.keyspace`
# for all instances of this class.
# Override `#keyspace` for per-object evaluation.
keyspace :some_other_keyspace
def find_user(id)
# `session` is a vanilla Cassandra::Session
# connected to `some_other_keyspace`
session.execute('SELECT * FROM users WHERE id = ?;', arguments: [id])
end
end
See the Connection README for more on features and usage.
Cassie provides simple commands to control Cassandra execution in *nix development. These simplify execution and reduce output to provide faster management of your Cassandra processes.
$ cassie start
Starting Cassandra...
[✓] Cassandra Running
$ cassie stop
Stopping Cassandra...
[✓] Cassandra Stopped
$ cassie stop
Couldn't single out a Cassandra process.
- Is cqlsh running?
- Kill all cassandra processes with --all
- 9542 | /usr/local/apache-cassandra-3.0.8/bin/cqlsh.py
- 2832 | org.apache.cassandra.service.CassandraDaemon
$ cassie stop --all
Stopping Cassandra...
[✓] Cassandra Stopped
$ cassie restart
Stopping Cassandra...
[✓] Cassandra Stopped
Starting Cassandra...
[✓] Cassandra Running
$ cassie tail
Tailing Cassandra system log, Ctrl-C to stop...
/usr/local/cassandra/logs/system.log:
INFO [main] 2016-09-23 11:18:05,073 StorageService.java:1902 - Node localhost/127.0.0.1 state jump to NORMAL
INFO [main] 2016-09-23 11:18:05,215 NativeTransportService.java:75 - Netty using Java NIO event loop
INFO [main] 2016-09-23 11:18:05,343 Server.java:159 - Using Netty Version: [netty-buffer=netty-buffer-4.0.23.Final.208198c, netty-codec=netty-codec-4.0.23.Final.208198c, netty-codec-http=netty-codec-http-4.0.23.Final.208198c, netty-codec-socks=netty-codec-socks-4.0.23.Final.208198c, netty-common=netty-common-4.0.23.Final.208198c, netty-handler=netty-handler-4.0.23.Final.208198c, netty-transport=netty-transport-4.0.23.Final.208198c, netty-transport-rxtx=netty-transport-rxtx-4.0.23.Final.208198c, netty-transport-sctp=netty-transport-sctp-4.0.23.Final.208198c, netty-transport-udt=netty-transport-udt-4.0.23.Final.208198c]
INFO [main] 2016-09-23 11:18:05,344 Server.java:160 - Starting listening for CQL clients on localhost/127.0.0.1:9042 (unencrypted)...
INFO [main] 2016-09-23 11:18:05,407 CassandraDaemon.java:477 - Not starting RPC server as requested. Use JMX (StorageService->startRPCServer()) or nodetool (enablethrift) to start it
Cassie supports migration between schema states using semantically versioned, incremental migration files.
Schema Version information is stored in Cassandra persistence, in the cassie_schema.versions
table (configurable).
A schema file holds the current state of the schema in-repo, at db/cassandra/schema.rb
, (configurable).
Various cassie <task>
tasks are used to manage the schema version and migrations.
Task | Description |
---|---|
migrations:import | Import existing cassandra_migrations migration files and convert to semantic versioning |
migration:create | Generates an empty migration file prefixed with the next semantic version number |
migrate | Migrates the schema by running the up methods in any migrations starting after the current schema version |
migrate:reset | runs schema:reset and migrate |
schema:init | Create versioned migrations schema, and the environment's keyspace if it doesn't exist |
schema:version | Print the current schema version information for the Cassandra cluster |
schema:history | Print the the historical version information the current Cassandra cluster state |
schema:status | Print the the migration status for each local migration (up/down) |
schema:load | Creates the schema by executing the CQL schema in the schema file (db/cassandra/schema.rb by default) |
schema:drop | drop keyspace(s) |
schema:dump | Dumps the schema for all non-system keyspaces in CQL format (db/cassandra/schema.rb by default) |
schema:reset | runs schema:drop and schema:load |
schema:import | Create an initial migration based on the current Cassandra non-system schema |
See the Migrations README for more on features and usage.
Cassie provides base Query Classes to manage interactions to the database. Create application specific subclasses and construct queries with a simple CQL DSL.
class UserByUsernameQuery < Cassie::Query
select_from :users_by_username
where :username, :eq
consistency :quorum
end
UserByUsernameQuery.new.fetch_first(username: "eprothro")
=> #<Struct user_id=123, username="eprothro">
See the Queries README for more on features and usage.
Avoid making queries into the persistnace layer when you can afford it.
some_query = SomeQuery.new
some_query.extend(Cassie::Testing::Fake::Query)
some_query.session.rows = [{'user_id' => 123, 'username' => 'eprothro'}]
some_query.fetch
=> [#<Struct user_id=123, username="eprothro">]
some_query.session.last_statement
=> #<Cassandra::Statements::Simple:0x3ffde09930b8 @cql="SELECT * FROM users LIMIT 500;" @params=[]>
See the Testing README for more on features and usage.
Pull requests and issues are welcome. Please read the contributing guidelines.