Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

redis-accessor.js 3.6 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  1. const createRedisClient = require('./redis/create-client')
  2. const InMemoryRedis = require('redis-mock')
  3. const { promisify } = require('util')
  4. const { CI, NODE_ENV, REDIS_URL } = process.env
  5. // Do not use real a Redis client for CI, tests, or if the REDIS_URL is not provided
  6. const useRealRedis = !CI && NODE_ENV !== 'test' && !!REDIS_URL
  7. class RedisAccessor {
  8. constructor ({
  9. databaseNumber = 0,
  10. prefix = null,
  11. allowSetFailures = false,
  12. allowGetFailures = false,
  13. name = null
  14. } = {}) {
  15. const redisClient = useRealRedis
  16. ? createRedisClient({
  17. url: REDIS_URL,
  18. db: databaseNumber,
  19. name: name || 'redis-accessor'
  20. })
  21. : InMemoryRedis.createClient()
  22. this._client = redisClient
  23. this._prefix = prefix ? prefix.replace(/:+$/, '') + ':' : ''
  24. // Allow for graceful failures if a Redis SET operation fails?
  25. this._allowSetFailures = allowSetFailures === true
  26. // Allow for graceful failures if a Redis GET operation fails?
  27. this._allowGetFailures = allowGetFailures === true
  28. }
  29. /** @private */
  30. prefix (key) {
  31. if (typeof key !== 'string' || !key) {
  32. throw new TypeError(`Key must be a non-empty string but was: ${JSON.stringify(key)}`)
  33. }
  34. return this._prefix + key
  35. }
  36. static translateSetArguments (options = {}) {
  37. const setArgs = []
  38. const defaults = {
  39. newOnly: false,
  40. existingOnly: false,
  41. expireIn: null, // No expiration
  42. rollingExpiration: true
  43. }
  44. const opts = { ...defaults, ...options }
  45. if (opts.newOnly === true) {
  46. if (opts.existingOnly === true) {
  47. throw new TypeError('Misconfiguration: entry cannot be both new and existing')
  48. }
  49. setArgs.push('NX')
  50. } else if (opts.existingOnly === true) {
  51. setArgs.push('XX')
  52. }
  53. if (Number.isFinite(opts.expireIn)) {
  54. const ttl = Math.round(opts.expireIn)
  55. if (ttl < 1) {
  56. throw new TypeError('Misconfiguration: cannot set a TTL of less than 1 millisecond')
  57. }
  58. setArgs.push('PX')
  59. setArgs.push(ttl)
  60. }
  61. // otherwise there is no expiration
  62. if (opts.rollingExpiration === false) {
  63. if (opts.newOnly === true) {
  64. throw new TypeError('Misconfiguration: cannot keep an existing TTL on a new entry')
  65. }
  66. setArgs.push('KEEPTTL')
  67. }
  68. return setArgs
  69. }
  70. async set (key, value, options = {}) {
  71. const setAsync = promisify(this._client.set).bind(this._client)
  72. const fullKey = this.prefix(key)
  73. if (typeof value !== 'string' || !value) {
  74. throw new TypeError(`Value must be a non-empty string but was: ${JSON.stringify(value)}`)
  75. }
  76. // Handle optional arguments
  77. const setArgs = this.constructor.translateSetArguments(options)
  78. try {
  79. const result = await setAsync(fullKey, value, ...setArgs)
  80. return result === 'OK'
  81. } catch (err) {
  82. const errorText = `Failed to set value in Redis.
  83. Key: ${fullKey}
  84. Error: ${err.message}`
  85. if (this._allowSetFailures === true) {
  86. // Allow for graceful failure
  87. console.error(errorText)
  88. return false
  89. }
  90. throw new Error(errorText)
  91. }
  92. }
  93. async get (key) {
  94. const getAsync = promisify(this._client.get).bind(this._client)
  95. const fullKey = this.prefix(key)
  96. try {
  97. const value = await getAsync(fullKey)
  98. return value
  99. } catch (err) {
  100. const errorText = `Failed to get value from Redis.
  101. Key: ${fullKey}
  102. Error: ${err.message}`
  103. if (this._allowGetFailures === true) {
  104. // Allow for graceful failure
  105. console.error(errorText)
  106. return null
  107. }
  108. throw new Error(errorText)
  109. }
  110. }
  111. }
  112. module.exports = RedisAccessor
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...