• Stars
    star
    49
  • Rank 585,874 (Top 12 %)
  • Language
    Crystal
  • License
    MIT License
  • Created over 4 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Pure-Crystal Redis client, supporting clustering, RedisJSON, RediSearch, RedisGraph, and RedisTimeSeries

redis

A pure-Crystal implementation of the Redis protocol

Installation

  1. Add the dependency to your shard.yml:

    dependencies:
      redis:
        github: jgaskins/redis
  2. Run shards

Usage

require "redis"

redis = Redis::Client.new # Defaults to `localhost` port 6379

redis.set "foo", "bar"
redis.get "foo" # => "bar"

redis.incr "counter" # => 1
redis.incr "counter" # => 2
redis.decr "counter" # => 1

redis.del "foo", "counter" # => 2

Pipelined queries

To mitigate latency with multiple queries whose inputs and outputs are completely independent of each other, you can "pipeline" your queries by sending them all at once before reading them. To do this, you can use the pipeline method:

redis.pipeline do |pipe|
  pipe.incr "foo"
  pipe.set "bar", "baz"
  pipe.lpush "my-list", "my value"
end

The return value of pipeline will be an array containing the values of each of those calls in the order they were sent. So in this case, it might be [1, nil, 2] to match the return values of incr, set, and lpush, respectively.

Transactions

The Redis MULTI command begins a transaction, so you can use the multi method to execute a transaction against the server:

redis.multi do |txn|
  txn.set "foo", "bar"
  txn.incr "baz"
  txn.lpush "my-list", "my value"
end

The transaction is automatically committed with EXEC at the end of the block. If an exception occurs within the block, the transaction will be rolled back with DISCARD before exiting the block.

You may also call txn.discard, which will effectively disable the transaction (all further methods called on the transaction do nothing), but will not exit the block. You will need to exit the block explicitly with break if there are operations within the block that cannot be rolled back, such as sending an email or sending a request to a third-party API.

The reason for this is that the only way to exit a containing block from an inner method in Crystal is to raise an exception, and this library chooses not to use exceptions for flow control.

Beyond localhost

To use a Redis server that isn't at localhost:6379, pass a URI to the client. For example, if you store it in your shell environment:

redis = Redis::Client.new(URI.parse(ENV["REDIS_URL"]))

# ... or ...

redis = Redis::Client.from_env("REDIS_URL")

To connect via SSL, make sure you use the rediss:// URL scheme. If your Redis server requires a password or uses a different database slot than 0, make sure you include them in the URL:

redis = Redis::Client.new(URI.parse("rediss://:[email protected]/3"))

Connection Pool

The Redis::Client maintains a connection pool, so there is no need to run your own within your application. When you execute a command on the Redis::Client, it is automatically executed against a connection. When you execute a pipeline or transaction with multi, all commands within that block will automatically be routed to the same connection.

Configuration

For this shard, we use the following default setting (outside of the Standard Lib defaults);

max_idle_pool_size = 25

You can override this manually using the URI parameters. All other settings follow the DB::Pool defaults.

The behaviour of the connection pool can be configured from a set of query string parameters in the connection URI.

Name Default value
initial_pool_size 1
max_pool_size 0 (unlimited)
max_idle_pool_size 1
checkout_timeout 5.0 (seconds)
retry_attempts 1
retry_delay 1.0 (seconds)

See Crystal guides to learn more.

Example

pool_params = "?initial_pool_size=1&max_pool_size=10&checkout_timeout=10&retry_attempts=2&retry_delay=0.5&max_idle_pool_size=50"
redis = Redis::Client.new(URI.parse("redis://localhost:6379/0#{pool_params}"))

Recommendations

If you encounter any issues, keep these setting the same;

  • initial_pool_size
  • max_pool_size
  • max_idle_pool_size

Example:

initial_pool_size = 50
max_pool_size = 50
max_idle_pool_size = 50

TCP Keep-Alive

The Redis::Client uses a pool of Redis::Connection under the hood. Within Redis::Connection we create a TCPSocket, which can accept keepalive params. The TCP keepalive settings can help you mitigate Redis connection stability issues.

NOTE: This behaviour is disabled by default. See Configuration below on how to enable it.

Configuration

For this shard, we use the following override setting;

Name Default value
keepalive false
keepalive_count 3
keepalive_idle 60
keepalive_interval 30

You can override this manually using the URI parameters. The settings above have proven to have good results in production environments. However, every environment is different, so tweaking these settings may be necessary.

See Crystal API to learn more.

Example

params = "?keepalive=true&keepalive_count=5&keepalive_idle=10&keepalive_interval=15"

redis = Redis::Client.new(URI.parse("redis://localhost:6379/0#{params}"))
# or direct connections
redis = Redis::Connection.new(URI.parse("redis://localhost:6379/0#{params}"))

Recommendations

Enable this setting with the defaults if you are encountering connection issues.

Example:

params = "?keepalive=true"

redis = Redis::Client.new(URI.parse("redis://localhost:6379/0#{params}"))
# or direct connections
redis = Redis::Connection.new(URI.parse("redis://localhost:6379/0#{params}"))

Development

Make sure you have a Redis or KeyDB server running locally on port 6379.

Redis must be installed with a stack server for the full text search (ft) and time series modules (ts) in order for all specs to run.

With Docker

You can use this for your docker-compose file

redis:
  image: redis/redis-stack-server
  ports:
    - "6379:6379"

With Homebrew

Install the redis-stack from homebrew

Contributing

  1. Fork it (https://github.com/jgaskins/redis/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

More Repositories

1

perpetuity

Persistence gem for Ruby objects using the Data Mapper pattern
Ruby
251
star
2

live_view

Server-rendering for client-side interactions
Crystal
72
star
3

grpc

Pure-Crystal implementation of gRPC
Crystal
69
star
4

primalize

Convert objects into primitives for serialization
Ruby
42
star
5

neo4j.cr

Pure-Crystal implementation of Neo4j's Bolt protocol
Crystal
30
star
6

crystal_live_view_example

Proof of concept for a Crystal version of Phoenix Live View
Crystal
23
star
7

armature

Roda-inspired HTTP framework for Crystal, providing routing, sessions, forms, etc
Crystal
20
star
8

method_pattern

Pattern matching for Ruby methods
Ruby
20
star
9

nats

NATS client in pure Crystal with JetStream support
Crystal
20
star
10

interro

Framework for query objects and model objects
Crystal
19
star
11

turbo

Crystal
18
star
12

moku

ActivityPub server
Crystal
15
star
13

hot_topic

A fake HTTP client for making requests to your HTTP::Handler classes
Crystal
13
star
14

opal-slim

Sprockets integration to compile Slim templates for Opal apps
Ruby
13
star
15

datadog

Datadog client for APM tracing and metrics in Crystal
Crystal
12
star
16

opentelemetry

OpenTelemetry SDK and exporters for the Crystal language
Crystal
12
star
17

kubernetes

Kubernetes API client in Crystal, providing a framework for writing controllers/operators
Crystal
11
star
18

aws

AWS Client for the Crystal programming language
Crystal
11
star
19

mpsc

Multi-Producer/Single-Consumer channels in Crystal
Crystal
10
star
20

perpetuity-postgres

Postgres adapter for Perpetuity
Ruby
10
star
21

primalize-jsonapi

Ruby
8
star
22

grpc_example

Example of using the GRPC Crystal shard in an application
Crystal
8
star
23

rails_app_operator

Kubernetes Rails app operator, allowing simple day-1 Rails deployment to a Kubernetes cluster
Crystal
8
star
24

slow_ride

Ruby
5
star
25

elasticsearch

Elasticsearch client for Crystal
Crystal
4
star
26

opal_blog

An example of using the Clearwater framework with Opal/Rails
Ruby
4
star
27

pennant

Feature flags in Crystal applications with pluggable backends (in-memory and Redis currently supported)
Crystal
3
star
28

perpetuity-mongodb

Ruby
3
star
29

degradable

Automate degradation of a service or feature when a failure threshold has passed. Coordinates multiple instances via Redis.
Crystal
2
star
30

crystal-docker-example

Crystal
2
star
31

postgis

PostGIS extensions for the Crystal Postgres client
Crystal
2
star
32

clearwater

Front-end Ruby framework using Opal
2
star
33

clearwater-roda-example

An example app comparing Clearwater and React in a Roda app
Ruby
1
star
34

redis-cluster-operator

Crystal
1
star
35

turbolinks-vs-clearwater

Performance comparison of Turbolinks and a virtual DOM
Ruby
1
star
36

github

GitHub API client
Crystal
1
star
37

sidekiq_lucky_example

Crystal
1
star
38

mastodon_intake_debugging

Crystal
1
star
39

advent_of_code-2018

My solutions for Advent of Code 2018
Crystal
1
star
40

pg-age

Crystal
1
star
41

cloud_events

Implementation of CloudEvents in Crystal
Crystal
1
star
42

fauxrem-redis

Redis/DEV Hackathon 2022 entry
Crystal
1
star
43

bugsnag

Crystal
1
star
44

k8s_rails_example

Example Dockerized Rails app for deployment on Kubernetes
Ruby
1
star
45

redis-docs

Documentation for the jgaskins/redis Crystal shard
HTML
1
star
46

opal-pusher

Opal bindings for the Pusher JS API
Ruby
1
star
47

nats-streaming

Crystal
1
star
48

opal-google_maps

Gem for using Google Maps in a Ruby front-end app
Ruby
1
star
49

jgaskins.github.io

HTML
1
star
50

example_crystal_app

Crystal
1
star
51

server_rendered_clearwater_example

Server-rendered Clearwater example
Ruby
1
star
52

clearwater_todomvc

TodoMVC on Clearwater
Ruby
1
star
53

big_array

Array type that can hold more than 2**32-1 elements
Crystal
1
star
54

mprop-crystal

Crystal port of Mitchell Henke's Phoenix.LiveView Milwaukee Property Search app
CSS
1
star