@@ -168,47 +168,114 @@ of flags, and features, but are very low level for general use.
168
168
def meta_multiget(
169
169
self,
170
170
keys: List[Key],
171
- flags: Optional[Set[Flag]] = None,
172
- int_flags: Optional[Dict[IntFlag, int]] = None,
173
- token_flags: Optional[Dict[TokenFlag, bytes]] = None,
171
+ flags: Optional[RequestFlags] = None,
172
+ failure_handling: FailureHandling = DEFAULT_FAILURE_HANDLING,
174
173
) -> Dict[Key, ReadResponse]:
175
174
176
175
def meta_get(
177
176
self,
178
177
key: Key,
179
- flags: Optional[Set[Flag]] = None,
180
- int_flags: Optional[Dict[IntFlag, int]] = None,
181
- token_flags: Optional[Dict[TokenFlag, bytes]] = None,
178
+ flags: Optional[RequestFlags] = None,
179
+ failure_handling: FailureHandling = DEFAULT_FAILURE_HANDLING,
182
180
) -> ReadResponse:
183
181
184
182
def meta_set(
185
183
self,
186
184
key: Key,
187
185
value: Any,
188
186
ttl: int,
189
- flags: Optional[Set[Flag]] = None,
190
- int_flags: Optional[Dict[IntFlag, int]] = None,
191
- token_flags: Optional[Dict[TokenFlag, bytes]] = None,
187
+ flags: Optional[RequestFlags] = None,
188
+ failure_handling: FailureHandling = DEFAULT_FAILURE_HANDLING,
192
189
) -> WriteResponse:
193
190
194
191
def meta_delete(
195
192
self,
196
193
key: Key,
197
- flags: Optional[Set[Flag]] = None,
198
- int_flags: Optional[Dict[IntFlag, int]] = None,
199
- token_flags: Optional[Dict[TokenFlag, bytes]] = None,
194
+ flags: Optional[RequestFlags] = None,
195
+ failure_handling: FailureHandling = DEFAULT_FAILURE_HANDLING,
200
196
) -> WriteResponse:
201
197
202
198
def meta_arithmetic(
203
199
self,
204
200
key: Key,
205
- flags: Optional[Set[Flag]] = None,
206
- int_flags: Optional[Dict[IntFlag, int]] = None,
207
- token_flags: Optional[Dict[TokenFlag, bytes]] = None,
201
+ flags: Optional[RequestFlags] = None,
202
+ failure_handling: FailureHandling = DEFAULT_FAILURE_HANDLING,
208
203
) -> WriteResponse:
209
204
```
210
-
211
- You won't use this api unless you are implementing some custom high-level
205
+ ### Special arguments:
206
+ ` RequestFlags ` has the following arguments:
207
+ * ` no_reply ` : Set to True if the server should not send a response
208
+ * ` return_client_flag ` : Set to True if the server should return the client flag
209
+ * ` return_cas_token ` : Set to True if the server should return the CAS token
210
+ * ` return_value ` : Set to True if the server should return the value (Default)
211
+ * ` return_ttl ` : Set to True if the server should return the TTL
212
+ * ` return_size ` : Set to True if the server should return the size (useful if when paired with return_value=False, to get the size of the value)
213
+ * ` return_last_access ` : Set to True if the server should return the last access time
214
+ * ` return_fetched ` : Set to True if the server should return the fetched flag
215
+ * ` return_key ` : Set to True if the server should return the key in the response
216
+ * ` no_update_lru ` : Set to True if the server should not update the LRU on this access
217
+ * ` mark_stale ` : Set to True if the server should mark the value as stale
218
+ * ` cache_ttl ` : The TTL to set on the key
219
+ * ` recache_ttl ` : The TTL to use for recache policy
220
+ * ` vivify_on_miss_ttl ` : The TTL to use when vivifying a value on a miss
221
+ * ` client_flag ` : The client flag to store along the value (Useful to store value type, compression, etc)
222
+ * ` ma_initial_value ` : For arithmetic operations, the initial value to use (if the key does not exist)
223
+ * ` ma_delta_value ` : For arithmetic operations, the delta value to use
224
+ * ` cas_token ` : The CAS token to use when storing the value in the cache
225
+ * ` opaque ` : The opaque flag (will be echoed back in the response)
226
+ * ` mode ` : The mode to use when storing the value in the cache. See SET_MODE_ * and MA_MODE_ * constants
227
+
228
+ ` FailureHandling ` controls how the failures are handled. Has the arguments:
229
+ * ` raise_on_server_error ` : (` Optional[bool] ` ) Wether to raise on error:
230
+ - ` True ` : Raises on server errors
231
+ - ` False ` : Returns miss for reads and false on writes
232
+ - ` None ` (DEFAULT): Use the raise on error setting configured in the Router
233
+ * ` track_write_failures``: ( ` bool`) Wether to track failures:
234
+ - ` True ` (DEFAULT): Track write failures
235
+ - ` False ` : Do not notify write failures
236
+
237
+ The default settings are usually good, but there are situations when you want control.
238
+ For example, a refill (populating an entry that was missing on cache) doesn't need to
239
+ track write failures. If fails to be written, the cache will still be empty, so no need
240
+ to track that as a write failure. Similarly sometimes you need to know if a write failed
241
+ due to CAS semantics, or because it was an add vs when it is due to server failure.
242
+
243
+ ### Responses:
244
+ The responses are either:
245
+ * ` ReadResponse ` : ` Union[Miss, Value, Success] `
246
+ * ` WriteResponse ` : ` Union[Success, NotStored, Conflict, Miss] `
247
+
248
+ Which are:
249
+ * ` Miss ` : For key not found. No arguments
250
+ * ` Success ` : Successfull operation
251
+ - ` flags ` : ` ResponseFlags `
252
+ * ` Value ` : For value responses
253
+ - ` flags ` : ` ResponseFlags `
254
+ - ` size ` : ` int ` Size of the value
255
+ - ` value ` : ` Any ` The value
256
+ * ` NotStored ` : Not stored, for example "add" on exising key. No arguments.
257
+ * ` Conflict ` : Not stored, for example due to CAS mismatch. No arguments.
258
+
259
+ The ` ResponseFlags ` contains the all the returned flags. This metadata gives a lot of
260
+ control and posibilities, it is the strength of the meta protocol:
261
+ * ` cas_token ` : Compare-And-Swap token (integer value) or ` None ` if not returned
262
+ * ` fetched ` :
263
+ - ` True ` if fetched since being set
264
+ - ` False ` if not fetched since being set
265
+ - ` None ` if the server did not return this flag info
266
+ * ` last_access ` : time in seconds since last access (integer value) or ` None ` if not returned
267
+ * ` ttl ` : time in seconds until the value expires (integer value) or ` None ` if not returned
268
+ - The special value ` -1 ` represents if the key will never expire
269
+ * ` client_flag ` : integer value or ` None ` if not returned
270
+ * ` win ` :
271
+ - ` True ` if the client won the right to repopulate
272
+ - ` False ` if the client lost the right to repopulate
273
+ - ` None ` if the server did not return a win/lose flag
274
+ * ` stale ` : ` True ` if the value is stale, ` False ` otherwise
275
+ * ` real_size ` : integer value or ` None ` if not returned
276
+ * ` opaque flag ` : bytes value or ` None ` if not returned
277
+
278
+ NOTE: You shouldn't use this api directly, unless you are implementing some custom high-level
212
279
command. See below for the usual memcache api.
213
280
214
281
## High level commands:
@@ -233,6 +300,33 @@ Invalidation...
233
300
stale_policy: Optional[StalePolicy] = None,
234
301
set_mode: SetMode = SetMode.SET, # Other are ADD, REPLACE, APPEND...
235
302
) -> bool:
303
+ """
304
+ Write a value using the specified `set_mode`
305
+ """
306
+
307
+ def refill(
308
+ self: HighLevelCommandMixinWithMetaCommands,
309
+ key: Union[Key, str],
310
+ value: Any,
311
+ ttl: int,
312
+ no_reply: bool = False,
313
+ ) -> bool:
314
+ """
315
+ Try to refill a value.
316
+
317
+ Use this method when you got a cache miss, read from DB and
318
+ are trying to refill the value.
319
+
320
+ DO NOT USE to write new state.
321
+
322
+ It will:
323
+ * use "ADD" mode, so it will fail if the value is already
324
+ present in cache.
325
+ * It will also disable write failure tracking. The write
326
+ failure tracking is often used to invalidate keys that
327
+ fail to be written. Since this is not writting new state,
328
+ there is no need to track failures.
329
+ """
236
330
237
331
def delete(
238
332
self,
@@ -241,6 +335,12 @@ Invalidation...
241
335
no_reply: bool = False,
242
336
stale_policy: Optional[StalePolicy] = None,
243
337
) -> bool:
338
+ """
339
+ Returns True if the key existed and it was deleted.
340
+ If the key is not found in the cache it will return False. If
341
+ you just want to the key to be deleted not caring of whether
342
+ it exists or not, use invalidate() instead.
343
+ """
244
344
245
345
def invalidate(
246
346
self,
@@ -249,13 +349,19 @@ Invalidation...
249
349
no_reply: bool = False,
250
350
stale_policy: Optional[StalePolicy] = None,
251
351
) -> bool:
352
+ """
353
+ Returns true of the key deleted or it didn't exist anyway
354
+ """
252
355
253
356
def touch(
254
357
self,
255
358
key: Union[Key, str],
256
359
ttl: int,
257
360
no_reply: bool = False,
258
361
) -> bool:
362
+ """
363
+ Modify the TTL of a key without retrieving the value
364
+ """
259
365
260
366
def get_or_lease(
261
367
self,
@@ -264,6 +370,13 @@ Invalidation...
264
370
touch_ttl: Optional[int] = None,
265
371
recache_policy: Optional[RecachePolicy] = None,
266
372
) -> Optional[Any]:
373
+ """
374
+ Get a key. On miss try to get a lease.
375
+
376
+ Guarantees only one cache client will get the miss and
377
+ gets to repopulate cache, while the others are blocked
378
+ waiting (according to the settings in the LeasePolicy)
379
+ """
267
380
268
381
def get_or_lease_cas(
269
382
self,
@@ -272,27 +385,41 @@ Invalidation...
272
385
touch_ttl: Optional[int] = None,
273
386
recache_policy: Optional[RecachePolicy] = None,
274
387
) -> Tuple[Optional[Any], Optional[int]]:
388
+ """
389
+ Same as get_or_lease(), but also return the CAS token so
390
+ it can be used during writes and detect races
391
+ """
275
392
276
393
def get(
277
394
self,
278
395
key: Union[Key, str],
279
396
touch_ttl: Optional[int] = None,
280
397
recache_policy: Optional[RecachePolicy] = None,
281
398
) -> Optional[Any]:
399
+ """
400
+ Get a key
401
+ """
282
402
283
403
def multi_get(
284
404
self,
285
405
keys: List[Union[Key, str]],
286
406
touch_ttl: Optional[int] = None,
287
407
recache_policy: Optional[RecachePolicy] = None,
288
408
) -> Dict[Key, Optional[Any]]:
409
+ """
410
+ Get multiple keys at once
411
+ """
289
412
290
413
def get_cas(
291
414
self,
292
415
key: Union[Key, str],
293
416
touch_ttl: Optional[int] = None,
294
417
recache_policy: Optional[RecachePolicy] = None,
295
418
) -> Tuple[Optional[Any], Optional[int]]:
419
+ """
420
+ Same as get(), but also return the CAS token so
421
+ it can be used during writes and detect races
422
+ """
296
423
297
424
def get_typed(
298
425
self,
@@ -302,6 +429,9 @@ Invalidation...
302
429
recache_policy: Optional[RecachePolicy] = None,
303
430
error_on_type_mismatch: bool = False,
304
431
) -> Optional[T]:
432
+ """
433
+ Same as get(), but ensure the type matched the provided cls
434
+ """
305
435
306
436
def get_cas_typed(
307
437
self,
@@ -311,6 +441,10 @@ Invalidation...
311
441
recache_policy: Optional[RecachePolicy] = None,
312
442
error_on_type_mismatch: bool = False,
313
443
) -> Tuple[Optional[T], Optional[int]]:
444
+ """
445
+ Same as get_typed(), but also return the CAS token so
446
+ it can be used during writes and detect races
447
+ """
314
448
315
449
def delta(
316
450
self,
@@ -320,6 +454,9 @@ Invalidation...
320
454
no_reply: bool = False,
321
455
cas_token: Optional[int] = None,
322
456
) -> bool:
457
+ """
458
+ Increment/Decrement a key that contains a counter
459
+ """
323
460
324
461
def delta_initialize(
325
462
self,
@@ -331,6 +468,11 @@ Invalidation...
331
468
no_reply: bool = False,
332
469
cas_token: Optional[int] = None,
333
470
) -> bool:
471
+ """
472
+ Increment/Decrement a key that contains a counter,
473
+ creating and setting it to the initial value if the
474
+ counter does not exist.
475
+ """
334
476
335
477
def delta_and_get(
336
478
self,
@@ -339,6 +481,9 @@ Invalidation...
339
481
refresh_ttl: Optional[int] = None,
340
482
cas_token: Optional[int] = None,
341
483
) -> Optional[int]:
484
+ """
485
+ Same as delta(), but return the resulting value
486
+ """
342
487
343
488
def delta_initialize_and_get(
344
489
self,
@@ -349,9 +494,19 @@ Invalidation...
349
494
refresh_ttl: Optional[int] = None,
350
495
cas_token: Optional[int] = None,
351
496
) -> Optional[int]:
497
+ """
498
+ Same as delta_initialize(), but return the resulting value
499
+ """
352
500
```
353
501
354
- # Anti-dogpiling techniques
502
+ # Reliability, consistency and best practices
503
+ We have published a deep-dive into some of the techniques to keep
504
+ cache consistent and reliable under high load that RevenueCat uses,
505
+ available thanks to this cache client.
506
+
507
+ See: https://www.revenuecat.com/blog/engineering/data-caching-revenuecat/
508
+
509
+ ## Anti-dogpiling, preventing thundering herds:
355
510
Some commands receive ` RecachePolicy ` , ` StalePolicy ` and ` LeasePolicy ` for the
356
511
advanced anti-dogpiling control needed in high-qps environments:
357
512
0 commit comments