# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
This site has an agentic ask interface you may use to query the documentation dynamically by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://redis-cache.ortusbooks.com/index.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

---

# Introduction

The Ortus Redis Extension is a native Lucee Extension that allows your CFML server to connect to a Redis/Cluster and leverage it for built-in caching, session storage, Pub/Sub Messaging, and much more

## Ortus Redis Extension v3.x Docs

<img src="https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2F8IkBoRp1LPQCusLG6QgO%2Fortus-redis-extension.png?alt=media&amp;token=192caecc-c563-4ace-b013-bf70500fc4a8" alt="Ortus Redis Lucee Extension" width="375">

The [Ortus Redis Extension](https://www.ortussolutions.com/products/redis-lucee) is a **native** Lucee Extension that allows your CFML server to connect to a Redis server or a Redis Cluster and leverage it for built-in caching, session storage, Pub/Sub Messaging, and document storage.

> Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker. It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperlogs and geospatial indexes with radius queries. Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster. [Learn More](https://redis.io/topics/introduction)

### Requirements

* Lucee 5.1.0 and above
* Redis Standalone or Cluster 4.0.X and above

### Commercial Product

This Lucee extension is a commercial product by Ortus Solutions. You will need to purchase a license: <https://www.ortussolutions.com/products/redis-lucee>.

### Features In A Nutshell

* Add Redis native functionality to any Lucee server
* Install at server level (Available to all contexts)
* Create Cache connections in the Lucee web administrator or via `Application.cfc` to connect to any network-accessible Redis cluster
* Set and get objects from Redis via standard CFML functions and tags (`cachePut(), cacheGet(), cfcache action="get|put"`)
* Fully supports all built-in Lucee cache functions including wildcard filters
* Seamlessly distribute storage of the following to any Redis Cluster
  * Lucee session storage
  * Lucee client storage
  * Lucee Ram resources (ram://...)
* Seamlessly cache the following to any timeout-sensitive Redis key
  * Results of database queries
  * Results of deterministic functions
  * Complex or simple objects in your application's code
  * Cached templates (`cfcache action="content|cache|serverCache"`)
* Extremely lightweight and fast
* Ability to publish and subscribe to Redis channels for pub/sub capabilities: <https://redis.io/topics/pubsub>
* Native Redis functions:
  * `RedisGetCluster( cacheName )`
  * `RedisGetClusterNodes( cacheName )`
  * `RedisGetConnectionPool( cacheName )`
  * `RedisGetProvider( cacheName )`
  * `RedisPublish( channel, message, cacheName )`
  * `RedisSubscribe( subscriber, channels, cacheName )`

### Support

The Ortus Redis Extension is a commercial product by Ortus Solutions. If you have purchased a license then you are entitled to customer support. You can either visit our support page to contact us or create an issue in our bug tracker.

* Support Page: <https://www.ortussolutions.com/services/support>
* Bug Tracker: <https://ortussolutions.atlassian.net/browse/LRE>


# Release History

A collection of all the major releases of this extension

In this section, you will find the release notes for each version we release under this major version. If you are looking for the release notes of previous major versions, use the version switcher at the top left of this documentation book. Here is a breakdown of our major version releases.

## Version 3.0.x

The 3.x series focuses on JDK11 minimal support and complete internal refactoring to leverage Gradle as a build system for all Java components. It also makes a major bump in all of our internal libraries.

## Version 2.x

Version 2 is a major extension rewrite to support Redis Clusters and Redis Pub/Sub functionalities.  It also included major updates to all the underlying Java architecture, Code Quality Metrics, Testing, and much more.

## Version 1.a

The birth of Redis for Lucee


# What's new with 3.5.x

### New Feature

Redis Client ( Jedis ) updated to v6.0.0

Redis v8 Compatibility

Lucee 6 Compatibility


# What's New With 3.0.0

July 19, 2023

### New Feature

LRE-48 - Update Redis extension driver ( Jedis ) to v4.4.3 ( v3.0 ) and v4.4.6 ( v3.2.0 )

LRE-54 - Add settings for SSL transport and usernames to `RedisClusterCache`

LRE-55 - Add setting for username to `RedisCache`

LRE-58- Added `redisLock` tag for distributed locking ( v3.3.0 )

### Additional Changes

Converted extension build process to use Gradle and compile against Lucee v5.4


# What's New With 2.2.0

April 1, 2023

### New Feature

[LRE-52](https://ortussolutions.atlassian.net/browse/LRE-52) Add support for cluster passwords, read timeout, max connections in connection information for the cluster connections


# What's New With 2.1.0

March 21, 2023

### New Feature

[LRE-50](https://ortussolutions.atlassian.net/browse/LRE-50) adds the ability to specify an array of hosts and ports on connections

### Bug

[LRE-49](https://ortussolutions.atlassian.net/browse/LRE-49) fixes null pointer exceptions on `ClusterCache` connection

### Improvement

[LRE-44](https://ortussolutions.atlassian.net/browse/LRE-44) Allow Environment Variable Support for License Info

### Task

[LRE-51](https://ortussolutions.atlassian.net/browse/LRE-51) Remove provider copies as it is now not used


# What's New With 2.x

Version 2 is a major rewrite of our Java Extension. You can find the release notes and the major areas of improvement here.

## Major Updates

### Redis Logical Database Support

By default Redis supports the concept of logical [databases](https://redis.io/commands/select/).  In our previous extension you could only connect to **database 0**, which is the default database.  This meant that all cache connections had to connect to this database and add a prefix key per connection to avoid collisions.

Now, you can add which logical database to connect to and partition your installation by logical database rather than by prefix.  Thus, providing great separation of concerns for your connections and applications.  On your cache connection details for the Redis Cache, just select which database number to connect to.  That's it!

![](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FXSpEWMfSIuxqkdiQbexF%2Fimage.png?alt=media\&token=9af950d0-6c00-455f-81ff-f088ef7abc64)

### Redis Cluster Support

![Cluster Support](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FfbCUgEBvVGpMinK0J9Qk%2FScreen%20Shot%202021-11-19%20at%2010.27.51%20AM.png?alt=media\&token=50c962a2-deed-4fc4-aac7-afe5385d9138)

We have added the capability to connect to not only standalone Redis instances via our `Redis Cache` connector, but we have now introduced the `Redis Cluster Cache` connector. This connector can connect to any Redis Cluster and give you all the great features our extension gives.

![Cluster Configuration](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2Fjp7VfHIqovEJHaKUTEWD%2FScreen%20Shot%202021-11-19%20at%2010.34.04%20AM.png?alt=media\&token=8a591892-6e6d-47a4-9d45-55075723f408)

### Redis Cluster Functions

We have also introduced several new functions for usage in a cluster cache:

| Function                            | Description                                                                                                    |
| ----------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `RedisGetCluster( cacheName )`      | Get access to the underlying Redis Cluster Java class so you can execute native cluster commands.              |
| `RedisGetClusterNodes( cacheName )` | Returns a struct of all the nodes and their appropriate Java classes representing their node connection pools. |

### Redis Pub/Sub

![https://dingyuliang.me/wp-content/uploads/2018/02/redis-pubsub-768x407.png](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FB03LOLgaPyifvwwsrOsr%2Fimage.png?alt=media\&token=2b076fbb-b257-4da2-abb6-b2ab3206d685)

We have introduced the capability for your CFML code to now leverage Redis Publish and Subscribe constructs. This will allow your CFML code to have native messaging via Redis.

{% embed url="<https://redis.io/topics/pubsub>" %}
Documentation
{% endembed %}

#### What is Pub/Sub?

> Redis Pub/Sub implements the Publish/Subscribe messaging paradigm. This decoupling of publishers and subscribers can allow for greater scalability and a more dynamic network topology.

1. Subscribers express interest in one or more channels (literal channels or pattern channels).
2. Publishers send messages into channels.
3. Redis will push these messages into different subscribers which have matched the channel's message.

#### Pub/Sub Functions

In order to leverage this pattern you will use the following two functions:

| Function                                            | Description                                                                  |
| --------------------------------------------------- | ---------------------------------------------------------------------------- |
| `RedisPublish( channel, message, cacheName )`       | Publish a message into Redis into a specific channel.                        |
| `RedisSubscribe( subscriber, channels, cacheName )` | Subscribe to a channel for messages using a closure/lambda or a listener CFC |

#### Publish Example

```javascript
// Publish Example
<h2>Publishing messages...</h2>
<cfflush>
<cfscript>
	RedisPublish( "test-channel", "Hola mi amigo" );
	RedisPublish( "test-channel", "Hola mi amigo2" );
	RedisPublish( "test-channel", "Hola mi amigo Redis" );
</cfscript>
<h2>Finished publishing messages</h2>
```

#### Subscribe Example

```javascript
<cfscript>
// Subscribe with closure
closureSubscriber = redisSubscribe( ( channel, message ) => {
	writeDump( var="Message received on channel #arguments.channel#, #arguments.message#", output="console" );
}, "test-channel" );

// Subscribe with CFC
cfcSubscriber = redisSubscribe( new Subscriber(), "test-channel" );

</cfscript>
<h1>Subscription started!! Check the logs!</h1>
```

#### Subscriber Listener CFC

```javascript
component {

	public void function onMessage( String channel, String message ) {
		writeDump( var="Subscriber CFC -> onMessage called :#arguments.toString()#", output="console" );
	}

	public void function onPMessage( String pattern, String channel, String message ) {
		writeDump( var="Subscriber CFC -> onPMessage called :#arguments.toString()#", output="console" );
	}

	public void function onSubscribe( String channel, numeric subscribedChannels ) {
		writeDump( var="Subscriber CFC -> onSubscribe called :#arguments.toString()#", output="console" );
	}

	public void function onUnsubscribe( String channel, numeric subscribedChannels ) {
		writeDump( var="Subscriber CFC -> onUnsubscribe called :#arguments.toString()#", output="console" );
	}

	public void function onPUnsubscribe( String pattern, numeric subscribedChannels ) {
		writeDump( var="Subscriber CFC -> onPUnsubscribe called :#arguments.toString()#", output="console" );
	}

	public void function onPSubscribe( String pattern, numeric subscribedChannels ) {
		writeDump( var="Subscriber CFC -> onPSubscribe called :#arguments.toString()#", output="console" );
	}

}
```

### Code Quality

We have completely refactored our internal Java code to include code quality metrics via [SonarLint](#major-updates), upgrades to JDK 8-11 constructs, internal streams and so much more.

### Better Exception Handling

Dealing with exceptions is always nasty. However, in this release we have optimized all exceptions so better debugging is added and we can pinpoint bugs and improvements.

## Release Notes

### Fixed

* [LRE-35](https://ortussolutions.atlassian.net/browse/LRE-35) cache filters for getting entries was not working
* [LRE-32](https://ortussolutions.atlassian.net/browse/LRE-32) getting all values/entries was not passing a built key, so return struct was always null
* [LRE-23](https://ortussolutions.atlassian.net/browse/LRE-23) LicenseHelper not validating all editions of similar product skus

### Added

* [LRE-41](https://ortussolutions.atlassian.net/browse/LRE-41) Ability to choose which database to connect to in Redis, apart from 0 being the default
* [LRE-40](https://ortussolutions.atlassian.net/browse/LRE-40) Migration of docs to gitbook
* [LRE-39](https://ortussolutions.atlassian.net/browse/LRE-39) New redisSubscribe() so you can subscribe with closures/lambdas or CFCs to listen to Redis messages
* [LRE-38](https://ortussolutions.atlassian.net/browse/LRE-38) New redisPublish() UDF so you can publish messages into the Redis cluster
* [LRE-37](https://ortussolutions.atlassian.net/browse/LRE-37) New UDF redisGetClusterNodes() to get a map of cluster node objects
* [LRE-36](https://ortussolutions.atlassian.net/browse/LRE-36) Redis Cluster protocol support (RedisCluster, Sentinel, AWS, DigitalOcean)
* [LRE-33](https://ortussolutions.atlassian.net/browse/LRE-33) Redis publish and subscribe features
* [LRE-31](https://ortussolutions.atlassian.net/browse/LRE-31) New native cfml function: `redisGetCluster()` to get access to the native redis cluster manager
* [LRE-30](https://ortussolutions.atlassian.net/browse/LRE-30) Improve all exception handling to show exception messages
* [LRE-29](https://ortussolutions.atlassian.net/browse/LRE-29) Creation of a base class to share between cache implementations
* [LRE-28](https://ortussolutions.atlassian.net/browse/LRE-28) Add docker redis cluster support
* [LRE-27](https://ortussolutions.atlassian.net/browse/LRE-27) Update Jedis to 2.9.3
* [LRE-25](https://ortussolutions.atlassian.net/browse/LRE-25) Allow for a new setting to allow for case-sensitive mode instead of case-insensitive mode (default)


# Changelog

All notable changes to this project will be documented in this file.

## Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

***

### \[3.5.0] => 2025-JUL-09

#### Added

* Redis v8 Test Coverage and Compatibility
* Lucee 6 CI Matrix Test Coverage

#### Changed

* [LRE-63](https://ortussolutions.atlassian.net/browse/LRE-63) - Redis Client Library ( Jedis ) to v6.0.0

### \[3.4.1] => 2025-JUN-20

#### Added

* Lucee 6 Compatibility

### \[3.4.0] => 2024-DEC-04

#### Changed

* Redis Client Library ( Jedis ) to v5.2.0

#### Fixed

* Fixes connection release issues with distributed lock and Redis single-node mode

### \[3.3.2] => 2024-DEC-02

#### Fixed

* LRE-62 - Resolve issue where distributed lock connections were not being released

### \[3.3.1] => 2024-APR-03

#### Fixed

* Fixed cluster authentication being lost due to upstream java object close-with-resources behavior

### \[3.3.0] => 2024-FEB-15

#### Added

* Adds `cfredislock` and `redisLock` tags for tag-based and script syntax
* Adds `maxIdleConnections` and `maxIdleTime` configuration settings for Redis Cluster cache
* Adds getCache method to `RedisCacheUtils`

#### Fixed

* LRE-57 : Cluster cache commands was not closing the jedis pool on some operations

#### Updated

* Github actions to latest versions

### \[3.2.0] => 2023-NOV-25

#### Added

* Add settings for `poolWaitTimeout` and `socketTimeout` for RedisCache and RedisClusterCache connections

#### Changed

* Redis Client Library ( Jedis ) to v4.4.6
* Changed default max connections to 100 for initial reliability in HA deployments

### \[3.1.0] => 2023-SEP-11

#### Fixed

* Fixed unparseable date format by Lucee admin

### \[3.0.0] => 2023-JUL-19

#### Changed

* Converted extension build to Gradle OSGI Bundle
* Redis Client Library ( Jedis ) to v4.4.3

#### Added

* Added SSL and username support to RedisClusterCache configuration
* Added username support to RedisCache ( non-cluster ) configuration

### \[2.2.1] => 2022-APR-06

#### Fixed

* Fixes an issue with property file license activation

### \[2.2.0] => 2022-MAR-31

#### Added

* Added support for cluster password authentication
* Added cluster cache configuration for read timeouts
* Added cluster cache configuration for max number of pool connections

### \[2.1.0] => 2022-MAR-16

#### Fixed

* Fixes an issue with Cluster cache connections due to uninstantiated connection manager

#### Added

* Added support for environmental configuration of license variables
  * `REDIS_EXTENSION_EMAIL`
  * `REDIS_EXTENSION_LICENSE_KEY`
  * `REDIS_EXTENSION_SERVER_TYPE`
  * `REDIS_EXTENSION_ACTIVATION_CODE`
* Added support for an array of hostnames and ports to the configuration ( e.g. hosts=redis1.myhost.com,redis2.myhost.com port=6379,6377 )

### \[2.0.0] => 2022-AUG-05

#### Fixed

* [LRE-35](https://ortussolutions.atlassian.net/browse/LRE-35) cache filters for getting entries was not working
* [LRE-32](https://ortussolutions.atlassian.net/browse/LRE-32) getting all values/entries was not passing a built key, so return struct was always null
* [LRE-23](https://ortussolutions.atlassian.net/browse/LRE-23) LicenseHelper not validating all editions of similar product skus

#### Added

* [LRE-41](https://ortussolutions.atlassian.net/browse/LRE-41) Ability to choose which database to connect to in Redis, apart from 0 being the default
* [LRE-40](https://ortussolutions.atlassian.net/browse/LRE-40) Migration of docs to gitbook
* [LRE-39](https://ortussolutions.atlassian.net/browse/LRE-39) New redisSubscribe() so you can subscribe with closures/lambdas or CFCs to listen to Redis messages
* [LRE-38](https://ortussolutions.atlassian.net/browse/LRE-38) New redisPublish() UDF so you can publish messages into the Redis cluster
* [LRE-37](https://ortussolutions.atlassian.net/browse/LRE-37) New UDF redisGetClusterNodes() to get a map of cluster node objects
* [LRE-36](https://ortussolutions.atlassian.net/browse/LRE-36) Redis Cluster protocol support (RedisCluster, Sentinel, AWS, DigitalOcean)
* [LRE-33](https://ortussolutions.atlassian.net/browse/LRE-33) Redis publish and subscribe features
* [LRE-31](https://ortussolutions.atlassian.net/browse/LRE-31) New native cfml function: redisGetCluster() to get access to the native redis cluster manager
* [LRE-30](https://ortussolutions.atlassian.net/browse/LRE-30) Improve all exception handling to show exception messages
* [LRE-29](https://ortussolutions.atlassian.net/browse/LRE-29) Creation of a base class to share between cache implementations
* [LRE-28](https://ortussolutions.atlassian.net/browse/LRE-28) Add docker redis cluster support
* [LRE-27](https://ortussolutions.atlassian.net/browse/LRE-27) Update Jedis to 2.9.3
* [LRE-25](https://ortussolutions.atlassian.net/browse/LRE-25) Allow for a new setting to allow for case-sensitive mode instead of case-insensitive mode (default)

### \[1.4.0] => 2019-NOV-5

* `New Features`
  * Added a log4j bridge and custom appender so all log messages from the Redis library will not go out to the out logs in Lucee
* `Improvements`
  * Added all members of the `RedisConnection` class to be public/static so they can be inspected and reused
  * Added a `getConnectionKeys()` in the `RedisConnection` class to see which caches are configured and how
  * Added `RuntTimeExceptions and IOExceptions` whenever a Redis connection cannot be made to improve errors
  * Added more context when exceptions happen to the error messages
  * Converted all connection pool access to try's with resources for auto-closing and better code visibility
  * Coverted all `valueList()` and `entryLIst()` to leverage parallel streams for performance
* `Bugs`
  * Fixes an issue which caused the extension to fail on Lucee v5.2.9 and v5.3.x

### \[1.3.0] => 2019-SEP-30

* Added ability to set the following new settings on a cache connection:
  * Timeout
  * use SSL
  * Password
  * Max Connections
  * Max Idle Connections

### \[1.2.0] => 2019-MAR-05

* Init methods on the cache constructor are not static - <https://ortussolutions.atlassian.net/browse/LRE-1>
* Auto publishing
* S3 Publishing automated
* Added more verbose logging
* Added more logging for exception handling
* Major fix for session expirations when using session clusters with Lucee
* Removed tests source from final package to reduce binary size

### \[1.1.0] => 2018-JAN-16

* Minor fixes on Logging


# About This Book

The source code for this book is hosted in GitHub:

{% embed url="<https://github.com/ortus-docs/redis-cache>" %}

You can freely contribute to it and submit pull requests. The contents of this book is copyright by [Ortus Solutions, Corp](http://www.ortussolutions.com) and cannot be altered or reproduced without author's consent. All content is provided *"As-Is"* and can be freely distributed.

* The majority of code examples in this book are done in `cfscript`.
* The majority of code generation and running of examples are done via **CommandBox**: The ColdFusion (CFML) CLI, Package Manager, REPL - <https://www.ortussolutions.com/products/commandbox>​

## External Trademarks & Copyrights <a href="#external-trademarks-and-copyrights" id="external-trademarks-and-copyrights"></a>

Redis is a copyright and trademark of Redis Labs, Inc.

## Notice of Liability <a href="#notice-of-liability" id="notice-of-liability"></a>

The information in this book is distributed “as is”, without warranty. The author and Ortus Solutions, Corp shall not have any liability to any person or entity with respect to loss or damage caused or alleged to be caused directly or indirectly by the content of this training book, software and resources described in it.

## Contributing <a href="#contributing" id="contributing"></a>

We highly encourage contribution to this book and our open source software. The source code for this book can be found in our GitHub repository where you can submit pull requests.

## Charitable Proceeds <a href="#charitable-proceeds" id="charitable-proceeds"></a>

10% of the proceeds of this book will go to charity to support orphaned kids in El Salvador - [https://www.harvesting.org/](https://www.harvesting.org). So please donate and purchase the printed version of this book, every book sold can help a child for almost 2 months.

### Shalom Children's Home <a href="#shalom-childrens-home" id="shalom-childrens-home"></a>

{% embed url="<https://harvesting.org>" %}
[www.harvesting.org](http://www.harvesting.org)
{% endembed %}

**Shalom Children’s Home** is one of the ministries that is dear to our hearts located in El Salvador. During the 12 year civil war that ended in 1990, many children were left orphaned or abandoned by parents who fled El Salvador. The Benners saw the need to help these children and received 13 children in 1982. Little by little, more children came on their own, churches and the government brought children to them for care, and the Shalom Children’s Home was founded.

Shalom now cares for over 80 children in El Salvador, from newborns to 18 years old. They receive shelter, clothing, food, medical care, education and life skills training in a Christian environment. The home is supported by a child sponsorship program.

We have personally supported Shalom for over 6 years now; it is a place of blessing for many children in El Salvador that either have no families or have been abandoned. This is good earth to seed and plant.


# Installation

Getting started with the Ortus Redis Extension

## Redis Setup <a href="#redis-setup" id="redis-setup"></a>

You will need to install a [Redis Server](https://redis.io) separately. Your Redis cluster can be a single node, or multiple nodes. The nodes can be installed along side your web servers, or on a server farm of their own-- it's entirely up to you. You can also use [Docker](https://www.docker.com) to spin up a Redis instance. You can use the following Docker compose file for quick testing:

```yaml
version: '3'
services:

  redis_standalone:
    image: redis:6
    ports:
      - "6379:6379"
  redis_insight:
    image: redislabs/redisinsight:latest
    ports:
      - 8001:8001

  redis_cluster:
    image: grokzen/redis-cluster:6.2.0
    ports:
      - 7000-7005:7000-7005
    environment:
      - IP=0.0.0.0

```

{% hint style="info" %}
Using Docker, this will spin up a standalone Redis instance, a Redis cluster, and Redis insight for database inspection.
{% endhint %}

[Redis Insight](https://redis.com/redis-enterprise/redis-insight/) is a great product that it will give you full insights into your running Redis server or cluster.  It will help you analyze issues, inspect keys, values and much more.  Just navigate to the assigned port (8001) and start inspecting!

![Redis Insight](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FDmWr5pK52wJV5glbaaYD%2Fimage.png?alt=media\&token=ea8fcb21-85d2-4fe2-9d41-7787d846a14a)

{% embed url="<https://redis.com/redis-enterprise/redis-insight/>" %}

## Lucee Setup

The Redis extension is installed as a Lucee extension into any Lucee Server version `5.1.0` and above. The extension has to be installed at the **server level context**.

![](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FuJlVKSj2tbvw2XD7cvU4%2Fimage.png?alt=media\&token=31cdf28c-5e0c-42e1-b81f-5c10f74ed19c)

If installed in the server context, you can create server-level caches that are available to all web contexts in Lucee. The driver will also be available to all web contexts to add their own local caches or override caches if they need too as well.

### **ForgeBox Extension Provider**

In your Lucee Administrator under `Extension > Providers` paste in your Ortus provider URL (<https://www.forgebox.io>) and click `save`. Once added, the new provider URL should show up in the list as verified.&#x20;

{% hint style="warning" %}
Lucee has added ForgeBox as an extension provider as core to the project, so you might not need to do this step.
{% endhint %}

### **Installing the Extension**

Now click `Extensions > Applications` and wait for the list to load. There should be an item in the list called `Ortus Redis Cache`. You can activate it as a trial or as a full version with a license key after you install.

![](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FXLGa4d2x8DTEzpdfauY1%2Fimage.png?alt=media\&token=82ee7371-a87a-4718-bdd8-a2f753e4d909)

Click it and then click the `install` button to begin the installation process.

{% hint style="danger" %}
We recommend a complete server install so changes can take effect.
{% endhint %}

![](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FPR7egBsJnsIJ72372vT8%2Fimage.png?alt=media\&token=78e4c490-f889-48aa-814a-b9b62c296036)

#### Manual/Docker Installation

Lucee also allows you to deploy the extension file (.lex) into a special folder.  Lucee will detect the extension and automatically install it for you.  The location is the following

```
{lucee-server}/WEB-INF/lucee-server/deploy
```

Just drop the [ortus-redis-cache-2.0.0.lex](https://s3.amazonaws.com/downloads.ortussolutions.com/ortussolutions/lucee-extensions/ortus-redis-cache/2.0.0/ortus-redis-cache-2.0.0.lex) file in that folder, wait a few seconds and it will automatically install. You can drop the file there before the server is started or during a started server.

If anything goes wrong during the installation please verify the deploy logs in the following location

```
{lucee-server}/WEB-INF/lucee-server/context/logs/deploy.log
```

### **Activating the Extension**

![](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FeSYNwoWdBXjGh7tNVRQx%2Fimage.png?alt=media\&token=f093b300-7a69-4f00-bebc-4f78631d6ba7)\
\
Once the extension installs, you will now see a new menu item in the admin called `Ortus` with a sub menu called `Redis Cache`. Click this menu and you'll see the activation screen where you can enter the `license key` and `license email` with which you purchased the extension with.

{% hint style="warning" %}
If you do not see the menu, please do a complete restart of your Lucee Server.
{% endhint %}

You will also have to determine the type of server you are installing the extension to. Development or non-public facing servers are FREE of charge and by default receive up to 4 activations.

Production servers get only 1 activation, so make sure you choose the correct server type. Once you get all your information in the form, click on the `activate` button to finalize the installation. Choose the trial option if you don't have a license and just want to try out the extension. When the trial expires, the cache provider will stop working! **The trial is not for production use**.

![](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FFDObNeqeSj1zQCqFDLxE%2Fimage.png?alt=media\&token=b6981d09-1b72-4ef4-8278-9bdaf84a8599)

{% hint style="warning" %}
Development and staging servers are FREE of charge and each license includes up to 4 activations. Production licenses are on a per Lucee instance and are allowed 1 activation. If you have any activation issues, please contact us at <support@ortussolutions.com>. Also, make sure you have a valid internet connection in order to activate your product.\\
{% endhint %}

The Ortus Lucee Redis Extension should now be installed on your server and ready to use.

{% hint style="danger" %}
**Important**: Please note that the Redis Extension is licensed on a per-JVM basis or on a per container pack (5-container pack). You will need a license for each separate JVM, regardless of how many contexts (sites) are deployed in your Lucee installation. The typical setup is one JVM per physical/virtual server. Please email us at [support@ortussolutions.com](http://127.0.0.1:49339/docs/support@ortussolutions.com) if you have licensing questions.
{% endhint %}

### Downloading The Extension

If you will be using an offline installation or a Docker based installation, you can either follow the process above or download the extension and leverage a continuous integration server to build your images or server configurations. Please note that you will need a containerized server license to use this extension across multiple images.

<https://downloads.ortussolutions.com/#/ortussolutions/lucee-extensions/ortus-redis-cache/>

From our artifact repository, download the appropriate `lex` file and drop it into your Lucee deploy folder: `{lucee-server}/WEB-INF/lucee-server/deploy`. Once the engine starts, it will deploy the extension for you automatically.

#### Automatic Activation <a href="#automatic-activation" id="automatic-activation"></a>

If you will be using Kubernetes, Docker Swarm or any other orchestrator, you will need to automate the process of activation.  There are two methods of providing your activation information to the extension:

1. Activation via a `properties` file in the extension filesystem
2. Activation via environment variables

Since you will most likely want the server warmed up and ready to go, you may provide one of these two mechanisms in your build process.  With environment variable-based activation, there is no need to hard-code the license information in to the container build, though you may do so.  Simply supply these environment keys at runtime or via a .env file.

#### Environment Variable License Configuration

The environment variables used in activating the extension are:

* `REDIS_EXTENSION_EMAIL`  - The email address used to purchase your extension
* `REDIS_EXTENSION_LICENSE_KEY` - The license key you were provided at registration
* `REDIS_EXTENSION_SERVER_TYPE` - Optional, defaults to `Production`
* `REDIS_EXTENSION_ACTIVATION_CODE` - The activation code for your extension and server type.  Note that this can only be obtained manually through the Lucee admin, or by contacting our helpdesk.

To get an activation code, outside of the Lucee Admininstrator, please contact Ortus Solutions via the [helpdesk](https://ortussolutions.atlassian.net/servicedesk/customer/portal/9) or via email at <support@ortussolutions.com>\
\
If you wish to simply try out the application, you supply only one environment variable, which will activate a free extension trial:

```
REDIS_EXTENSION_SERVER_TYPE=Trial
```

To get your activation code, please contact Ortus Solutions via the [helpdesk](https://ortussolutions.atlassian.net/servicedesk/customer/portal/9) or via email at <support@ortussolutions.com>

#### Properties File License Configuration

To use the properties file method of license configuration, Create a `license.properties` file with the following content:

```bash
email=[The email address used to purchase your extension]
licenseKey=[The license key you were provided at registration]
activationCode=[The activation code for your extension and server type]
serverType=[ Activation type. Optional. Default to "Production"] 
```

And place it in the following location: `{lucee-server}/WEB-INF/lucee-server/context/context/ortus/redis/license.properties`

Upon server startup, the file will be sourced in and the extension activated.&#x20;


# Configuration

Learn how to configure the extension for operation

Once the extension is installed, you can begin to create cache connections and configure them either via the administrator, via the Application.cfc or via a CFConfig json file.

## Admin Cache Connection

![](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FOhnqE96lmh1hxl8Weorr%2Fimage.png?alt=media\&token=96ada276-1829-44ec-bc9a-52fbffa380f3)

To add a new cache, click on `Services > Cache` and you should see a list of existing caches. If there are no existing caches, you should be taken straight to the `create` screen.

![Creating a cache connection](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FhfsghSI21gAyGTSzYaPA%2FScreen%20Shot%202021-11-19%20at%2010.27.51%20AM.png?alt=media\&token=f0820b00-b4b2-4cdb-9368-f61badd59e1d)

You have two cache options with our extension:

* **Ortus Redis Cache** : For standalone or connecting to a single Redis instance
* **Ortus Redis Cluster Cache** : For connecting to a Redis Cluster

You will then be taken to a page of options for each of the Redis Cache implementations.

### RedisCache

<figure><img src="https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FPp5fyIhSl1aGVYxUvvx7%2FSingle-Cache-Admin.jpg?alt=media&amp;token=ce6f5a97-5f2f-44fc-8bba-d2064264d653" alt=""><figcaption></figcaption></figure>

The `RedisCache` is used for connecting to a single instance of Redis. That instance could be replicated, but that's another story. Let's check out the different options:

#### Storage

Check the `Storage` box if you want to be able to use this cache for session or client storage distribution.

#### Host

Enter the Redis server IP address or host name.

#### Port

The port of the Redis server.

#### Logical Database

The logical database to connect to in Redis. By default we connect to database 0.

#### Username

The Redis cluster username - only used when enabling [user-level access](https://docs.redis.com/latest/rs/security/access-control/manage-users/add-users/).

#### Password

The password of the Redis server, if any.

#### SSL

Enable SSL on the connection to the Redis Server.

#### Connection Timeout

The time in milliseconds to wait for a connection or throw an exception.

#### Socket Timeout

The cluster connection socket timeout in milliseconds

#### Pool Timeout

The the maximum amount of time, in milliseconds, to wait for a connection pool resource to become available

#### Max Connections

The maximum number of connections to allow to the Redis server.

#### Idle Connections

The maximum number of idle connections to keep in the pool to the Redis server

#### Cache Key Prefix

The default key prefix is `lucee-cache`. This will automatically prefix EVERY single cache item that goes into Redis. This will allow you to avoid collisions if you decide to register many Lucee caches or just to distinguish what comes from which cache connection.

#### Cache Key Case Sensitivity

By default all cache keys are transformed to lowercase to avoid any casing issues. However, if you want case sensitivity, then turn this option on.

#### Default

This is a Lucee feature where you can set the cache connection to be the default for all cache operations in Lucee (cacheGet(), cachePut(), etc). This can be one of the following or none at all.

![](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FE60eIfnWYodzTaUZwKzv%2Fimage.png?alt=media\&token=b8bef62b-3b5c-42a5-a73b-18849f40bb4f)

### RedisClusterCache

<figure><img src="https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FEvuLsPZOk3kK2Vd7IRiE%2FCluster-Cache-Admin.jpg?alt=media&amp;token=b3f51301-db51-434d-8024-59522b13e491" alt=""><figcaption></figcaption></figure>

The `RedisClusterCache` is used for connecting to a cluster of Redis instances. This can be using Sentinel, or vanilla clustering or Redis Enterprise or Redis AWS/DigitalOcean. Let's check out the different options:

#### Storage

Check the `Storage` box if you want to be able to use this cache for session or client storage distribution.

#### Host(s)

Enter a comma-delimited list of all the IPs or hosts in the cluster. Not all are needed, but you should at least enter some to have redundancy.

#### Port

The port of the Redis cluster.

#### SSL

Whether SSL transport is enabled

#### Username

The Redis cluster username - only used when enabling [user-level access](https://docs.redis.com/latest/rs/security/access-control/manage-users/add-users/).

#### Password

The Redis cluster password

#### Connection Timeout

The time in milliseconds to wait for a connection or throw an exception.

#### Read Timeout

The timeout for a read of data from the cluster - defaults to the connection timeout

#### Socket Timeout

The cluster connection socket timeout in milliseconds

#### Pool Timeout

The the maximum amount of time, in milliseconds, to wait for a connection pool resource to become available

#### Max Connections

The  maximum number of connections to the cluster allowed per pool - defaults to 50

#### Idle Timeout

The max idle time, in milliseconds, for a connection to remain in the pool.

#### Max Idle Connections

The maximum number of concurrently idle connections to retain in the pool

#### Max Attempts

The maximum number of connection attempts to make to the cluster.

#### Cache Key Prefix

The default key prefix is `lucee-cache`. This will automatically prefix EVERY single cache item that goes into Redis. This will allow you to avoid collisions if you decide to register many Lucee caches or just to distinguish what comes from which cache connection.

#### Cache Key Case Sensitivity

By default all cache keys are transformed to lowercase to avoid any casing issues. However, if you want case sensitivity, then turn this option on.

#### Default

This is a Lucee feature where you can set the cache connection to be the default for all cache operations in Lucee (cacheGet(), cachePut(), etc). This can be one of the following or none at all.

![](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FE60eIfnWYodzTaUZwKzv%2Fimage.png?alt=media\&token=b8bef62b-3b5c-42a5-a73b-18849f40bb4f)\\

## Application.cfc Connections

You can also add cache connections via your `Application.cfc` and avoid using the admin. Just open your `Application.cfc` and create a section under the pseudo-constructor (before the first function)

### RedisCache

```javascript
this.cache.connections["sessions"] = {
  class: 'ortus.extension.cache.redis.RedisCache', 
  storage: true, 
  custom: {
		"host":"127.0.0.1",
		"port":"6379"
		"username" : "",
		"password":"",
		"database" : "0",
		"useSSL": false,
		"timeout" : 2000,
		"socketTimeout" : 2000,
		"poolWaittimeout" : 1000,
		"maxConnections": 1000,
		"idleConnections": 10,
		"keyprefix":"lucee-cache",
		"cacheKeyCaseSensitivity" : false
	}, 
	default: 'object'
};
```

Please refer to the previous section to find out about what the custom options mean.

### RedisClusterCache

```javascript
this.cache.connections[ "myClusterCache" ] = {
  class: 'ortus.extension.cache.redis.RedisClusterCache', 
  storage: true, 
  custom: {
	"hosts":"127.0.0.1",
	"port":"7000",
	"username" : "",
	"password":"",
	"useSSL" : "",
	"timeout" : 2000,
	"readTimeout" : 2000,
	"socketTimeout" : 2000,
	"poolWaittimeout" : 1000,
	"maxAttempts" : 10,
	"maxConnections": 1000, 
	"maxIdleTime" : 30000,
	"maxIdleConnections" : 20, 
	"keyprefix":"lucee-cluster",			
	"cacheKeyCaseSensitivity" : false
}, 
default: 'object'
};
```

## CFConfig Connections

You can also leverage a `cfconfig.json` file to store the cache configurations and automatically load them into your CFML server via CommandBox.

```javascript
{
    "adminPassword" : "redis",
    "systemErr":"System",
    "systemOut":"System",
    "applicationTimeout":"1,0,0,0",
    "cacheDefaultObject":"sessions",
    "caches":{
        "sessions": {
            "class":"ortus.extension.cache.redis.RedisCache",
            "custom":{
                "cacheKeyCaseSensitivity":"false",
                "database" : "0",
                "idleConnections":"5",
                "maxConnections":"50",
		"username":"${REDIS_USERNAME}",
                "password":"${REDIS_PASSWORD}",
                "timeout":"2000",
                "useSSL":"false",
                "host":"${REDIS_HOST:127.0.0.1}",
                "keyprefix":"lucee-cache",
                "port":"${REDIS_PORT:6379}"
            },
            "readOnly":"false",
            "storage":"true"
        },
	"rediscluster": {
            "class":"ortus.extension.cache.redis.RedisClusterCache",
            "custom":{
                "hosts":"${REDIS_CLUSTER_HOSTS:127.0.0.1}",
                "keyprefix":"lucee-cluster",
                "username" : "${REDIS_CLUSTER_USERNAME}",
                "password" : "${REDIS_CLUSTER_PASSWORD}",
                "port":"${REDIS_CLUSTER_PORT:7000}",
		"useSSL" :"${REDIS_CLUSTER_USE_SSL:false}"
            },
            "readOnly":"false",
            "storage":"true"
        }
    },
    "inspectTemplate":"always",
    "requestTimeout":"0,0,0,50",
    "sessionMangement":"yes",
    "sessionTimeout":"0,0,30,0"
}
```

Please refer to the previous section to find out about what the custom options mean.


# Usage

There are a number of ways that the extension integrates Redis into your Lucee server. There is built-in caching, manual get/set of objects, and scope storage.  Discover our sections from the left menu.


# CFML

Use Redis from CFML natively

The first and easiest way to use your new cache is via the built-in cache functions and tags in CFML. You can specify the cache name to use, but by default Lucee will use the cache you have designated as your default `object` cache.

## **Caching Objects**

If you have selected your cache as the default `Object` cache in the admin, you can simply use functions like `cachePut()` and `cacheGet()`. Redis can handle arbitrary snippets of text (like HTML snippets) and even complex objects such as queries, arrays, or structs. The cache will automatically serialize the values and store them as text. They will be reconstituted when you retrieve them from the cache later.

```javascript
// Set a simple value into the default "object" cache for 2 days
cachePut( "key", "value", 2 );
// Get that value back
cacheGet( "key" );

// Set a value into a specific cache for 1 day
cachePut( "key", "value", 1, "myCacheName" );
// Get that value back
cacheGet( "key", "myCacheName" );

// Cache this array for 3 hours
cachePut( "myArray", [1,2,3,4,5], createTimeSpan(0,3,0,0) );
```

## **Caching Function Output**

Once you have selected a cache as the default `function` cache in the admin, you can use Redis to cache the results of oft-run functions. The cache key will be created for you automatically based on a hash of the method arguments thanks to Lucee. Cached functions should therefore be deterministic-- meaning the output of the function is purely a product of its parameters. Using function caching is easy, just add a `cachedwithin` attribute to the `cffunction` tag or function declaration.

```javascript
<!--- Cache results of this function for 5 minutes --->
<cffunction name="myFunc" cachedwithin="#createTimeSpan(0,0,5,0)#">
	<cfargument name="inputText">

	<cfreturn reverse(inputText)>
</cffunction>

<!--- First execution stores result in cache --->
<cfset result = myFunc("Brad Wood")>

<!--- subsequent call skips execution and pulls results from cache --->
<cfset result = myFunc("Brad Wood")>

<!--- Different parameters will create a new cache entry --->
<cfset result = myFunc("Luis Majano")>
```

This is what that function would look like in script

```javascript
function myFunc( inputText ) cachedwithin="#createTimeSpan(0,0,5,0)#" {
	return reverse(inputText);
}
```

{% hint style="danger" %}
**Important**: Lucee only supports caching functions that accept simple values as parameters. Therefore, a function that accepts an array would not be cacheable.
{% endhint %}

## **Caching Queries**

Once you have selected a cache as the default `query` cache in the admin, you can use Redis to cache the results of oft-run database queries. The cache key will be created for you automatically based on a hash of the SQL statement and its parameters thanks to Lucee. Using query caching is as easy as function caching, just add a cachedwithin attribute to your query.

```xml
<!--- Cache results of this query for 15 minutes --->
<cfquery datasource="datasourceName" name="qryTest" cachedwithin="#createTimeSpan(0,0,15,0)#">
	select *
	from [tableName]
</cfquery>
```

## **Per-application Cache Settings**

You can specify what caches are the default storage mechanism for functions, queries, objects, etc in the Lucee server and web administrator. There is one more programmatic level this can be configured as well.

The following settings are available in your `Application.cfc` to override at an application level. Remember, the "object" cache is used by default if no cache name is specified to functions such as `cachePut()` and `cacheGet()`.

You can also define an entire cache in your `Application.cfc` which makes your configuration completely portable.

```javascript
component{

	this.cache[ '<cache-name>' ] = {
		class  	= 'ortus.extension.cache.Redis.RedisCache',
		storage = false,
		custom={
			host = 'localhost',
			port = 6379,
			keyprefix = "lucee-prefix"
		}
	};

	this.cache.function="<cache-name>";
	this.cache.query="<cache-name>";
	this.cache.object="<cache-name>";
	this.cache.resource="<cache-name>";
	this.cache.template="<cache-name>";
}
```


# Distributed Locking

Introduced in version 3.3.0, the \<cfRedisLock>  tag offers distributed locking for clustered instances.

In clustered environments, it is often necessary to prevent multiple instances from executing methods at the same time, thus preventing collisions with data access and modificication.  The `<cfRedisLock>` tag ( `redisLock` in script ) allows the user to place a lock across all running instances in the cluster.

The tag functions exactly like `cflock/lock` with the exception of the `cache` and `bypass` arguments.  The the `bypass` argument can be useful in development environments when not using a distributed cache.

### Tag Usage

```
<cfRedisLock
    name="[ the name of the lock to place ]"
    cache="[ the configured redis cache to use for locking ]"
    throwOnTimeout="[ Defaults to true, whether to throw on failure to lock]"
    expires="[the max duration of the lock entry to exists in seconds - default 60s]"
    timeout="[the max time to wait for a lock to be acquired - default 2s]"
    bypass="[optional - if true will bypass the attempt to lock completely]"
>
.... do locked stuff here ...
</cfRedisLock>
```

### Script Usage

```
redisLock
    name="[ the name of the lock to place ]"
    cache="[ the configured redis cache to use for locking ]"
    throwOnTimeout="[ Defaults to true, whether to throw on failure to lock]"
    expires="[the max duration of the lock entry to exists in seconds - default 60s]"
    timeout="[the max time to wait for a lock to be acquired - default 2s]"
    bypass="[optional - if true will bypass the attempt to lock completely]"
{
.... do locked stuff here ...
}
```


# RAM Resources

Use Redis as a virtual file storage

Lucee has the concept and feature of virtual file systems. Our extension taps into it by allowing you to leverage the [`ram://`](ram://) resource to talk to Redis for storing documents and treating Redis like a big file system. This means that any `file` or `directory` related tag/function can work with a Redis RAM resource like: `fileRead(), fileWrite(), fileDelete(), directoryNew(), directoryList(), include`, etc. It even works when defining application mappings. You can define Redis to be the default cache for `resources` by selecting the `default` element in the cache details page and pointing it to `resource`.

{% hint style="danger" %}
**Important**: Please note that Lucee only allows you to determine 1 cache connection to be the default for either object, template, query, resource or function caching. You might end up creating different cache connections if you want to leverage them as **default** cache locations.
{% endhint %}

Once you setup Redis to be your default `resource` cache you can leverage it in many ways:

```javascript
// Create a mapping to it
this.mappings[ "/cluster-fs" ] = "ram://";


// Do some file operations
fileWrite( "/cluster-fs/suzi.txt", myContent );
include template="/cluster-fs/aop.cfm";
directoryList( "/cluster-fs/caches" );
```


# Scope Storage

Use Redis for session distribution

Lucee will allow you to seamlessly defer storage of your **session** and/or **client** scopes to Redis. You will set and access the scopes like you normally would in CFML, but behind the scenes Lucee stores a cache entry for each user containing their session/client variables in the Redis cluster.

This serves several purposes:

* Scopes are persisted across server restarts
* Lower memory usage since variables are **NOT** stored in the JVM's heap
* User sessions can be shared across web servers (**No more sticky sessions**)
* Redis cluster can be scaled out to handle whatever amount of users you need in a distributed fashion

This means you could take your single-server application with a heavy dependence on session/client variables, and scale it out to as many web servers as necessary behind a round-robin load balancer. Users are free to roam to any web server they want, and their session variables will follow them anywhere with no extra overhead. Perhaps you have millions of web site visitors and you're running out of heap space due to all the session storage. Push those sessions off to a distributed Redis layer that can scale out to meet demand, and that is no longer a bottleneck.

### Storage Option

For both session and client storage, you will need to check the `Storage` box when creating or editing the cache connection you want to use in the Lucee admin. Remember you can create multiple buckets in Redis to help manage your documents and segregate RAM.

![Storage Option](http://127.0.0.1:49339/docs/includes/shots/storage.png)

Set a cache as usable for `session` or `client` storage

### **Session**

Once the cache is created, enabling session storage is easy. In your Application.cfc simply confirm `sessionManagment` is turned on and set the following two settings as well in the `this` scope:

* `sessionType` : This is the type of session to use, valid values are `cfml` and `j2ee`. Make sure that you select `cfml` or the extension will NOT work.
* `sessionStorage` : This is the name of the cache defined in your Lucee administrator that you wish to store sessions in
* `sessionCluster` : This controls how/when session data is sent and retrieved from the cache.
  * `true`: Session data is primarily stored in cache. It is always pulled from the cache at the start of each request, and backed up at the end. Use this setting if you have multiple applications using cached storage and you want the full benefit of distributed sessions.
  * `false`: Session data is primarily stored in memory but backed up on every request to the cache. Session data is only pulled from the cache if it doesn't exist in memory. Set this to false if you only have one application using session cache storage and you simply want to persist session storage across restarts.

```javascript
component{
	this.name = "myApp";

	this.sessionType = "cfml";
	this.sessionManagement = true;
	this.sessionTimeout = createTimeSpan(0,0,30,0);

	// This is the name of the Redis cache to use
	this.sessionStorage = "SessionStorageCache";
	// Set this to true if you have more than 1 application
	this.sessionCluster = true;
}
```

{% hint style="danger" %}
**Important**: Make sure your session type is set to **cfml** or our extension will NOT work.
{% endhint %}

### **Client**

Storing your client scope in Redis is just as easy as session storage. In your Application.cfc confirm `clientManagement` is turned on and set the following two settings in the `this` scope:

* `clientStorage`: This is the name of the cache defined in your Lucee administrator that you wish to store client data in
* `clientCluster`: This controls how/when client data is sent and retrieved from the cache.
  * `true`: Client data is primarily stored in cache. It is always pulled from the cache at the start of each request, and backed up at the end. Use this setting if you have multiple applications using cached storage and you want the full benefit of distributed client data.
  * `false`: Client data is primarily stored in memory but backed up on every request to the cache. Client data is only pulled from the cache if it doesn't exist in memory. Set this to false if you only have one application using client cache storage and you simply want to persist client storage across restarts.

```javascript
component{
	this.name = "myApp";

	this.clientManagement = true;
	this.clientTimeout = createTimeSpan(25,0,0,0);

	// This is the name of the Redis cache to use
	this.clientStorage = "CientStorageCache";
	// Set this to true if you have more than 1 application
	this.clientCluster = true;
}
```


# Direct Java API

Go funky with the Redis extension

If you need more power or are familiar with the Redis Java API and want to use some features we haven't implemented yet, first [let us know](mailto:support@ortussolutions.com) so we can consider that addition in future version, and then head over to the Java Cluster to get direct access to the Redis Java SDK. Behind the scenes our extension leverages the [Jedis](https://github.com/xetorthio/jedis) library for Redis.

We have created several global CFML functions to interact with Redis

* `redisGetProvider( [cachename=default] )` - Retrieves the underlying Ortus Cache implementation
* `redisGetConnectionPool( [cachename=default] )` - Retrieves the Jedis pool for a specific connection cache
* `redisGetCluster( [cachename=default] )` - Retrieves the Jedis cache cluster
* `redisGetNodes( [cachename=default] )` - Retrieves a struct of the Jedis pool connections to the cluster.

#### `RedisGetProvider()` <a href="#redisgetprovider" id="redisgetprovider"></a>

`RedisGetProvider()` returns an instance to the Java class that Ortus wrote that proxies between the Redis client and Lucee. It implements `lucee.commons.io.cache.Cache`. For the most part you probably won't need this class, but there are a few methods in the Lucee cache interface that aren't available to you via CFML. You can also dump the class and check out all of its functions.

```javascript
// Get the Ortus Java Provider for the default object cache
myProvider = RedisGetProvider();

// Get the Ortus Java Provider for the queryStorage cache
myProvider = RedisGetProvider( "queryStorage" );

// Get all keys in the cache as a java.util.List
keys = myProvider.keys();

// Get all the values in the cache as a java.util.List
values = myProvider.values();
```

#### `RedisGetConnectionPool()` <a href="#redisgetconnectionpool" id="redisgetconnectionpool"></a>

`RedisGetConnectionPool()` Returns access to a cache's Redis Connection Jedis Pool. It implements `redis.clients.jedis.JedisPool` - <https://github.com/xetorthio/jedis/blob/master/src/main/java/redis/clients/jedis/JedisPool.java>. This will give you direct access to the Jedis Pool connection for that cache.

```
pool = redisGetConnectionPool( 'sessions' );

// Get funky....
```


# Publish/Subscribe

Use Redis as a complete real-time messaging broker

## What is Pub/Sub?

![https://dingyuliang.me/wp-content/uploads/2018/02/redis-pubsub-768x407.png](https://2355348434-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FltomKgiAAC9hwJTe8me6%2Fuploads%2FB03LOLgaPyifvwwsrOsr%2Fimage.png?alt=media\&token=2b076fbb-b257-4da2-abb6-b2ab3206d685)

We have introduced the capability for your CFML code to now leverage Redis Publish and Subscribe constructs. This will allow your CFML code to have native messaging via Redis.

{% embed url="<https://redis.io/topics/pubsub>" %}
Documentation
{% endembed %}

> Redis Pub/Sub implements the Publish/Subscribe messaging paradigm. This decoupling of publishers and subscribers can allow for greater scalability and a more dynamic network topology.

1. Subscribers express interest in one or more channels (literal channels or pattern channels).
2. Publishers send messages into channels.
3. Redis will push these messages into different subscribers which have matched the channel's message.

## Pub/Sub Functions

In order to leverage this pattern you will use the following two functions:

| Function                                            | Description                                                                                                                  |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `RedisPublish( channel, message, cacheName )`       | Publish a message into Redis into a specific channel. Returns how many subscribers are listening to the message and channel. |
| `RedisSubscribe( subscriber, channels, cacheName )` | Subscribe to a channel for messages using a closure/lambda or a listener CFC. Returns a `future` and a `subscriber.`         |

{% hint style="warning" %}
Pattern publishing and subscriptions are still not developed yet.
{% endhint %}

### Publish Example

```javascript
// Publish Example
<h2>Publishing messages...</h2>
<cfflush>
<cfscript>
	RedisPublish( "test-channel", "Hola mi amigo" );
	RedisPublish( "test-channel", "Hola mi amigo2" );
	RedisPublish( "test-channel", "Hola mi amigo Redis" );
</cfscript>
<h2>Finished publishing messages</h2>
```

The return of the `redisPublish()` function is numeric indicating how many subscribers received the message.

### Subscribe Example

```javascript
<cfscript>
// Subscribe with closure
closureSubscriber = redisSubscribe( ( channel, message ) => {
	writeDump( var="Message received on channel #arguments.channel#, #arguments.message#", output="console" );
}, "test-channel" );

// Subscribe with CFC
cfcSubscriber = redisSubscribe( new Subscriber(), "test-channel" );

</cfscript>
<h1>Subscription started!! Check the logs!</h1>
```

The `redisSubscribe()` function returns a struct with two keys in it:

* `future` - A completable future that is running your subscriber.
* `subscriber` - The Java Redis subscriber object you can use to inspect the subscription or unsubscribe from the calls via the `unsubscribe()` method.

### Subscriber Listener CFC

If you will be passing a CFC to the `redisSubscribe()` methods then you will need to implement some or all of the following functions.

```javascript
component {

	public void function onMessage( String channel, String message ) {
		writeDump( var="Subscriber CFC -> onMessage called :#arguments.toString()#", output="console" );
	}

	public void function onPMessage( String pattern, String channel, String message ) {
		writeDump( var="Subscriber CFC -> onPMessage called :#arguments.toString()#", output="console" );
	}

	public void function onSubscribe( String channel, numeric subscribedChannels ) {
		writeDump( var="Subscriber CFC -> onSubscribe called :#arguments.toString()#", output="console" );
	}

	public void function onUnsubscribe( String channel, numeric subscribedChannels ) {
		writeDump( var="Subscriber CFC -> onUnsubscribe called :#arguments.toString()#", output="console" );
	}

	public void function onPUnsubscribe( String pattern, numeric subscribedChannels ) {
		writeDump( var="Subscriber CFC -> onPUnsubscribe called :#arguments.toString()#", output="console" );
	}

	public void function onPSubscribe( String pattern, numeric subscribedChannels ) {
		writeDump( var="Subscriber CFC -> onPSubscribe called :#arguments.toString()#", output="console" );
	}

}
```


# Debugging

Issues? We all have them, learn how to cope with them

Here's a general list of troubleshooting steps if you're getting errors. The log files are VERY important since the error Lucee throws doesn't always contain the information you need. You will have to crack open your Lucee logs to get the actual error out.

* Look in the "out" and "err" logs for information. These are usually found in the servlet container's log directory. For instance, if you're using Tomcat, look in Tomcat's log directory. There are often messages logged there that never make it up to the CFML engine.
* The Log4J output of the underlying Redis Java SDK will be redirected to your Lucee server's "Application" log. Adjusting the logging level for this log will affect how much information you get from Redis.
* Always scroll to the bottom of Java stack traces to look for a "caused by" section which is the original error.
* If you are getting connection errors or Null pointer exceptions, check the spelling of your hostnames and ports and make sure Redis is actually running with the bucket name you specified in the config.
* Once the library connects, you should see lines in the "out" log showing the servers being connected to successfully.
* Open up the Redis web admin on one of your nodes and watch the "Ops per second" graph while you hit your app. If you see spikes in the graph every time you hit the app, then it's working!


