Skip to content

Commit

Permalink
Add support for Redis V4 through legacyMode (#345)
Browse files Browse the repository at this point in the history
The `legacyMode` option in `redis@v4` has matured enough such that all our tests pass now.

Also includes:

 - Remove legacy v3 -> v4 upgrade docs
 - Switch to double quotes for formatting

#336
  • Loading branch information
wavded authored Feb 4, 2022
1 parent 78997f9 commit 059c834
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 229 deletions.
34 changes: 17 additions & 17 deletions .github/release-drafter.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
name-template: "v$RESOLVED_VERSION"
tag-template: "v$RESOLVED_VERSION"
template: |
$CHANGES
category-template: '#### $TITLE'
change-template: '* #$NUMBER - $TITLE (@$AUTHOR)'
category-template: "#### $TITLE"
change-template: "* #$NUMBER - $TITLE (@$AUTHOR)"
categories:
- title: 'Breaking changes'
label: 'breaking'
- title: 'Enhancements'
label: 'enhancement'
- title: 'Bug fixes'
label: 'bug'
- title: 'Maintenance'
label: 'chore'
- title: "Breaking changes"
label: "breaking"
- title: "Enhancements"
label: "enhancement"
- title: "Bug fixes"
label: "bug"
- title: "Maintenance"
label: "chore"

version-resolver:
major:
labels:
- 'breaking'
- "breaking"
minor:
labels:
- 'enhancement'
- "enhancement"
patch:
labels:
- 'bug'
- 'chore'
- "bug"
- "chore"

exclude-labels:
- 'skip-changelog'
- "skip-changelog"
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node: ['12', '14', '16']
node: ["12", "14", "16"]
name: Node v${{ matrix.node }}
steps:
- uses: actions/checkout@v2
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ name: stale-issues-prs
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * *'
- cron: "0 0 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
with:
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
stale-pr-message: 'This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
close-issue-message: 'This issue was closed because it has been stalled for 5 days with no activity.'
stale-issue-message: "This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days."
stale-pr-message: "This PR is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days."
close-issue-message: "This issue was closed because it has been stalled for 5 days with no activity."
days-before-stale: 30
days-before-close: 5
stale-issue-label: stale
3 changes: 1 addition & 2 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"tabWidth": 2,
"semi": false,
"singleQuote": true
"semi": false
}
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
module.exports = require('./lib/connect-redis')
module.exports = require("./lib/connect-redis")
22 changes: 11 additions & 11 deletions lib/connect-redis.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ module.exports = function (session) {
// All callbacks should have a noop if none provided for compatibility
// with the most Redis clients.
const noop = () => {}
const TOMBSTONE = 'TOMBSTONE'
const TOMBSTONE = "TOMBSTONE"

class RedisStore extends Store {
constructor(options = {}) {
super(options)
if (!options.client) {
throw new Error('A client must be directly provided to the RedisStore')
throw new Error("A client must be directly provided to the RedisStore")
}

this.prefix = options.prefix == null ? 'sess:' : options.prefix
this.prefix = options.prefix == null ? "sess:" : options.prefix
this.scanCount = Number(options.scanCount) || 100
this.serializer = options.serializer || JSON
this.client = options.client
Expand Down Expand Up @@ -64,12 +64,12 @@ module.exports = function (session) {
return cb(er)
}
args.push(value)
args.push('EX', this._getTTL(sess))
args.push("EX", this._getTTL(sess))

let ttl = 1
if (!this.disableTTL) {
ttl = this._getTTL(sess)
args.push('EX', ttl)
args.push("EX", ttl)
}

if (ttl > 0) {
Expand All @@ -88,14 +88,14 @@ module.exports = function (session) {
let key = this.prefix + sid
this.client.expire(key, this._getTTL(sess), (err, ret) => {
if (err) return cb(err)
if (ret !== 1) return cb(null, 'EXPIRED')
cb(null, 'OK')
if (ret !== 1) return cb(null, "EXPIRED")
cb(null, "OK")
})
}

destroy(sid, cb = noop) {
let key = this.prefix + sid
this.client.set([key, TOMBSTONE, 'EX', 300], (err) => {
this.client.set([key, TOMBSTONE, "EX", 300], (err) => {
cb(err, 1)
})
}
Expand Down Expand Up @@ -163,12 +163,12 @@ module.exports = function (session) {
}

_getAllKeys(cb = noop) {
let pattern = this.prefix + '*'
let pattern = this.prefix + "*"
this._scanKeys({}, 0, pattern, this.scanCount, cb)
}

_scanKeys(keys = {}, cursor, pattern, count, cb = noop) {
let args = [cursor, 'match', pattern, 'count', count]
let args = [cursor, "match", pattern, "count", count]
this.client.scan(args, (err, data) => {
if (err) return cb(err)

Expand Down Expand Up @@ -196,7 +196,7 @@ module.exports = function (session) {
* @returns {boolean}
*/
function isObject(item) {
return item && typeof item === 'object' && !Array.isArray(item)
return item && typeof item === "object" && !Array.isArray(item)
}

/**
Expand Down
2 changes: 1 addition & 1 deletion license
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2010-2020 TJ Holowaychuk
Copyright (c) 2010-2022 TJ Holowaychuk

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
78 changes: 0 additions & 78 deletions migration-to-v4.md

This file was deleted.

7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"mockdate": "^2.0.5",
"nyc": "^15.0.1",
"prettier": "^2.0.5",
"redis": "^3.1.2",
"redis-v4": "npm:redis@4",
"redis-v3": "npm:redis@3",
"redis-mock": "^0.56.3"
},
"engines": {
Expand All @@ -33,7 +34,7 @@
"scripts": {
"test": "nyc tape \"test/*-test.js\"",
"lint": "eslint index.js test lib",
"fmt": "prettier --write \"**/*.{js,md,json,*rc}\"",
"fmt-check": "prettier --check \"**/*.{js,md,json,*rc}\""
"fmt": "prettier --write .",
"fmt-check": "prettier --check ."
}
}
33 changes: 19 additions & 14 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,44 @@

**connect-redis** provides Redis session storage for Express. Requires Redis >= `2.0.0`.

**Migrating to V4?** See [this guide](migration-to-v4.md) on what's changed.

## Installation

npm:

```sh
npm install redis@v3 connect-redis express-session
npm install redis connect-redis express-session
```

Yarn:

```sh
yarn add redis@v3 connect-redis express-session
yarn add redis connect-redis express-session
```

## API

```js
const { createClient } = require('redis')
const session = require('express-session')
const session = require("express-session")
let RedisStore = require("connect-redis")(session)

// redis@v4
const { createClient } = require("redis")
let redisClient = createClient({ legacyMode: true })
redisClient.connect().catch(console.error)

let RedisStore = require('connect-redis')(session)
// redis@v3
const { createClient } = require("redis")
let redisClient = createClient()

// ioredis
const Redis = require("ioredis")
let redisClient = new Redis()

app.use(
session({
store: new RedisStore({ client: redisClient }),
saveUninitialized: false,
secret: 'keyboard cat',
secret: "keyboard cat",
resave: false,
})
)
Expand All @@ -49,13 +57,10 @@ An instance of [`redis`][1] or a `redis` compatible client.

Known compatible and tested clients:

- [redis][1] (v3, **v4 currently is not supported**)
- [redis][1] (v3, v4 with `legacyMode: true`)
- [ioredis](https:/luin/ioredis)
- [redis-mock](https:/yeahoffline/redis-mock) for testing.

> Note: In order to use [redis][1] v4 for other things and connect-redis for sessions, an acceptable solution for the time being would be to add both v3 and v4 as dependencies and pass the v3 client in to connect-redis.
> [How to install multiple versions of same package?](https://stackoverflow.com/questions/26414587/how-to-install-multiple-versions-of-package-using-npm/56495651#56495651)
##### prefix

Key prefix in Redis (default: `sess:`).
Expand Down Expand Up @@ -108,7 +113,7 @@ Value used for _count_ parameter in [Redis `SCAN` command](https://redis.io/comm
#### How to log Redis errors?

```js
client.on('error', console.error)
client.on("error", console.error)
```

#### How do I handle lost connections to Redis?
Expand All @@ -119,7 +124,7 @@ By default, the [`redis`][1] client will [auto-reconnect](https:/mra
app.use(session(/* setup session here */))
app.use(function (req, res, next) {
if (!req.session) {
return next(new Error('oh no')) // handle error
return next(new Error("oh no")) // handle error
}
next() // otherwise continue
})
Expand Down
Loading

0 comments on commit 059c834

Please sign in to comment.