Skip to main content

Connections

redis

Commentary

added in 1.16.0

Connects to a Redis instance or cluster.

ShadowTraffic can connect to Redis using three different approaches: host and port 1, URL 2, or an array of cluster nodes 3. Regardless of the connection strategy, you can supply further authentication and connection parameters, like username/password and SSL. 4

The Redis connection currently supports three types of write operations: set 5, hset 6, and zadd 7. Each of them takes slightly different data to write with their keys.

Depending on the operation ShadowTraffic writes with, you can also supply contextually-specific parameters, like setting the expiration time for set keys. 8

Lastly, ShadowTraffic assumes all values written to Redis are strings. You can override this though and instruct ShadowTraffic to serialize your data as JSON before it's placed into Redis. 9


Examples

Connecting to a host/port

Supply a host and port for a minimal connection.

{
"connections": {
"redis": {
"kind": "redis",
"connectionConfigs": {
"host": "localhost",
"port": 6379
}
}
}
}

Connecting to a URL

If desired, you can directly connect with a url too.

{
"connections": {
"redis": {
"kind": "redis",
"connectionConfigs": {
"url": "redis://localhost:6379"
}
}
}
}

Connecting to a cluster

For connecting to a cluster of Redis nodes, pass in an array of clusterNodes.

{
"connections": {
"redis": {
"kind": "redis",
"connectionConfigs": {
"clusterNodes": [
{
"host": "redis-1",
"port": 6379
},
{
"host": "redis-2",
"port": 6379
},
{
"host": "redis-3",
"port": 6379
}
]
}
}
}
}

Supplying connection parameters

Irrespective of how you connect to Redis, you can also supply a username, password, database, and ssl optionality.

{
"connections": {
"redis": {
"kind": "redis",
"connectionConfigs": {
"host": "localhost",
"port": 6380,
"username": "admin",
"password": "admin",
"database": 0,
"ssl": true
}
}
}
}

Writing set operations

To execute a Redis set command, set op to the same name. set requires a value as part of its attributes map.

{
"generators": [
{
"op": "set",
"key": {
"_gen": "sequentialString",
"expr": "key-~d",
"cardinality": 3
},
"attributes": {
"value": {
"_gen": "oneOf",
"choices": [
"a",
"b",
"c"
]
}
}
}
],
"connections": {
"redis": {
"kind": "redis",
"connectionConfigs": {
"host": "localhost",
"port": 6379
}
}
}
}
[
{
"op": "set",
"opParams": null,
"key": "key-0",
"attributes": {
"value": "b"
}
},
{
"op": "set",
"opParams": null,
"key": "key-1",
"attributes": {
"value": "c"
}
},
{
"op": "set",
"opParams": null,
"key": "key-2",
"attributes": {
"value": "c"
}
},
{
"op": "set",
"opParams": null,
"key": "key-0",
"attributes": {
"value": "a"
}
},
{
"op": "set",
"opParams": null,
"key": "key-2",
"attributes": {
"value": "c"
}
}
]

Writing hset operations

Likewise, hset works similarly. hset requires both a field and value.

{
"op": "hset",
"key": {
"_gen": "sequentialString",
"expr": "user-~d",
"cardinality": 5
},
"attributes": {
"field": "tier",
"value": {
"_gen": "oneOf",
"choices": [
"gold",
"silver",
"bronze"
]
}
}
}
[
{
"op": "hset",
"opParams": null,
"key": "user-0",
"attributes": {
"field": "tier",
"value": "silver"
}
},
{
"op": "hset",
"opParams": null,
"key": "user-1",
"attributes": {
"field": "tier",
"value": "bronze"
}
},
{
"op": "hset",
"opParams": null,
"key": "user-2",
"attributes": {
"field": "tier",
"value": "bronze"
}
},
{
"op": "hset",
"opParams": null,
"key": "user-3",
"attributes": {
"field": "tier",
"value": "bronze"
}
},
{
"op": "hset",
"opParams": null,
"key": "user-4",
"attributes": {
"field": "tier",
"value": "gold"
}
}
]

Writing zadd operations

Finally, zadd follows the same pattern, requiring a score and member. Note that score must be a number, matching Redis's programming model.

{
"op": "zadd",
"key": {
"_gen": "sequentialString",
"expr": "user-~d",
"cardinality": 5
},
"attributes": {
"score": {
"_gen": "normalDistribution",
"mean": 10,
"sd": 2
},
"member": {
"_gen": "oneOf",
"choices": [
"blue",
"green",
"red"
]
}
}
}
[
{
"op": "zadd",
"opParams": null,
"key": "user-0",
"attributes": {
"score": 8.057562019117077,
"member": "blue"
}
},
{
"op": "zadd",
"opParams": null,
"key": "user-1",
"attributes": {
"score": 8.871880179475948,
"member": "red"
}
},
{
"op": "zadd",
"opParams": null,
"key": "user-2",
"attributes": {
"score": 13.703997152237063,
"member": "green"
}
},
{
"op": "zadd",
"opParams": null,
"key": "user-3",
"attributes": {
"score": 7.668764655731472,
"member": "green"
}
},
{
"op": "zadd",
"opParams": null,
"key": "user-4",
"attributes": {
"score": 8.368469904039284,
"member": "red"
}
}
]

Setting operation parameters

Set opParams to a map of operation-specific parameters. In particular:

set accepts:

  • ex: expiry time in seconds (integer)
  • px: expiry time in milliseconds (integer)
  • pxAt: expiry as a Unix timestamp in milliseconds (integer)
  • nx: only set the key if it does not already exist (boolean)
  • xx: only set the key if it already exists (boolean)

hset accepts:

  • nx: only set the field if it does not already exist (boolean)
  • ex: expiry time on the hash key in seconds (integer)
  • px: expiry time on the hash key in milliseconds (integer)

zadd accepts:

  • nx: only add new members, never update existing ones (boolean)
  • xx: only update existing members, never add new ones (boolean)
  • gt: only update if the new score is greater than the current score (boolean)
  • lt: only update if the new score is less than the current score (boolean)
  • ch: return the number of elements changed rather than only added (boolean)
  • incr: treat the score as an increment and return the new score (boolean)
{
"op": "set",
"opParams": {
"ex": 60
},
"key": {
"_gen": "sequentialString",
"expr": "key-~d",
"cardinality": 3
},
"attributes": {
"value": {
"_gen": "oneOf",
"choices": [
"a",
"b",
"c"
]
}
}
}

Serializing with JSON

By default, ShadowTraffic assumes all data you're writing to Redis will already be a string. But if you'd like ShadowTraffic to handle stringifying your data, set serialization to json. If your values are already a string, they won't be double serialized.

ShadowTraffic will serialize the key and all writeable attributes values.

{
"op": "hset",
"serialization": "json",
"key": {
"_gen": "sequentialString",
"expr": "user-~d",
"cardinality": 5
},
"attributes": {
"field": "tier",
"value": {
"_gen": "oneOf",
"choices": [
"gold",
"silver",
"bronze"
]
}
}
}

Specification

Connection JSON schema

{
"type": "object",
"properties": {
"kind": {
"type": "string",
"const": "redis"
},
"connectionConfigs": {
"type": "object",
"properties": {
"host": {
"type": "string"
},
"port": {
"type": "integer"
},
"clusterNodes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"host": {
"type": "string"
},
"port": {
"type": "integer"
}
},
"required": [
"host",
"port"
]
}
},
"url": {
"type": "string"
},
"user": {
"type": "string"
},
"password": {
"type": "string"
},
"ssl": {
"type": "boolean"
},
"database": {
"type": "integer",
"minimum": 0
}
},
"oneOf": [
{
"required": [
"clusterNodes"
]
},
{
"required": [
"host",
"port"
]
},
{
"required": [
"url"
]
}
]
}
},
"required": [
"connectionConfigs"
]
}

Generator JSON schema

{
"type": "object",
"properties": {
"connection": {
"type": "string"
},
"name": {
"type": "string"
},
"op": {
"type": "string",
"enum": [
"set",
"hset",
"zadd"
]
},
"serialization": {
"type": "string",
"enum": [
"none",
"json"
]
},
"key": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"opParams": {
"type": "object"
},
"attributes": {
"type": "object"
},
"localConfigs": {
"type": "object",
"properties": {
"throttleMs": {
"oneOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"maxEvents": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"kafkaKeyProtobufHint": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
},
"jsonSchemaHint": {
"type": "object"
},
"maxBytes": {
"type": "integer",
"minimum": 1
},
"discard": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"retainHistory": {
"type": "boolean"
}
},
"required": [
"rate"
]
},
"repeat": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"times": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
},
"required": [
"rate",
"times"
]
},
"sqlDdlHint": {
"type": "string"
},
"protobufSchemaHint": {
"type": "object",
"patternProperties": {
"^.*$": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
}
}
},
"schemaRegistrySubject": {
"type": "object"
},
"maxHistoryEvents": {
"type": "integer",
"minimum": 0
},
"maxMs": {
"type": "integer",
"minimum": 0
},
"time": {
"type": "integer"
},
"events": {
"type": "object",
"properties": {
"exactly": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
}
},
"delay": {
"type": "object",
"properties": {
"rate": {
"type": "number",
"minimum": 0,
"maximum": 1
},
"ms": {
"oneOf": [
{
"type": "integer",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
},
"required": [
"rate",
"ms"
]
},
"history": {
"type": "object",
"properties": {
"events": {
"type": "object",
"properties": {
"max": {
"type": "integer",
"minimum": 0
}
}
}
}
},
"avroSchemaHint": {
"type": "object"
},
"throttle": {
"type": "object",
"properties": {
"ms": {
"oneOf": [
{
"type": "number",
"minimum": 0
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
}
}
},
"throughput": {
"oneOf": [
{
"type": "integer",
"minimum": 1
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"timeMultiplier": {
"oneOf": [
{
"type": "number"
},
{
"type": "object",
"properties": {
"_gen": {
"type": "string"
}
},
"required": [
"_gen"
]
}
]
},
"kafkaValueProtobufHint": {
"type": "object",
"properties": {
"schemaFile": {
"type": "string"
},
"message": {
"type": "string"
}
},
"required": [
"schemaFile",
"message"
]
}
}
}
},
"required": [
"op",
"key"
]
}