1212import typing
1313from typing import Any
1414from typing import Mapping
15+ import warnings
1516
1617from ..api import CacheBackend
1718from ..api import NO_VALUE
1819from ... import util
1920
21+
2022if typing .TYPE_CHECKING :
2123 import bmemcached
2224 import memcache
@@ -323,16 +325,6 @@ class BMemcachedBackend(GenericMemcachedBackend):
323325 SASL is a standard for adding authentication mechanisms
324326 to protocols in a way that is protocol independent.
325327
326- SSL/TLS is a security layer on end-to-end communication.
327- It provides following benefits:
328-
329- * Encryption: Data is encrypted on the wire between
330- Memcached client and server.
331- * Authentication: Optionally, both server and client
332- authenticate each other.
333- * Integrity: Data is not tampered or altered when
334- transmitted between client and server
335-
336328 A typical configuration using username/password::
337329
338330 from dogpile.cache import make_region
@@ -441,27 +433,17 @@ class PyMemcacheBackend(GenericMemcachedBackend):
441433 cache misses.
442434
443435 dogpile.cache uses the ``HashClient`` from pymemcache in order to reduce
444- API differences when compared to other memcached client drivers. In short,
445- this allows the user to provide a single server or a list of memcached
436+ API differences when compared to other memcached client drivers.
437+ This allows the user to provide a single server or a list of memcached
446438 servers.
447439
448- The ``serde`` param defaults to ``pymemcache.serde.pickle_serde`` as the
449- legacy ``serde`` would always convert the stored data to binary.
450-
451- The ``default_noreply`` param defaults to False, otherwise the add command
452- would always return True causing the mutex not to work.
453-
454- SSL/TLS is a security layer on end-to-end communication.
455- It provides following benefits:
440+ Arguments which can be passed to the ``arguments``
441+ dictionary include:
456442
457- * Encryption: Data is encrypted on the wire between
458- Memcached client and server.
459- * Authentication: Optionally, both server and client
460- authenticate each other.
461- * Integrity: Data is not tampered or altered when
462- transmitted between client and server
443+ :param tls_context: optional TLS context, will be used for
444+ TLS connections.
463445
464- A typical configuration using tls_context::
446+ A typical configuration using tls_context::
465447
466448 import ssl
467449 from dogpile.cache import make_region
@@ -477,35 +459,131 @@ class PyMemcacheBackend(GenericMemcachedBackend):
477459 }
478460 )
479461
480- For advanced ways to configure TLS creating a more complex
481- tls_context visit https://docs.python.org/3/library/ssl.html
462+ .. seealso::
482463
483- Arguments which can be passed to the ``arguments``
484- dictionary include:
464+ `<https://docs.python.org/3/library/ssl.html>`_ - additional TLS
465+ documentation.
485466
486- :param tls_context: optional TLS context, will be used for
487- TLS connections.
488467 :param serde: optional "serde". Defaults to
489- ``pymemcache.serde.pickle_serde``
490- :param default_noreply: Defaults to False
468+ ``pymemcache.serde.pickle_serde``.
491469
492- """
470+ :param default_noreply: defaults to False. When set to True this flag
471+ enables the pymemcache "noreply" feature. See the pymemcache
472+ documentation for further details.
473+
474+ :param socket_keepalive: optional socket keepalive, will be used for
475+ TCP keepalive configuration. Use of this parameter requires pymemcache
476+ 3.5.0 or greater. This parameter
477+ accepts a
478+ `pymemcache.client.base.KeepAliveOpts
479+ <https://pymemcache.readthedocs.io/en/latest/apidoc/pymemcache.client.base.html#pymemcache.client.base.KeepaliveOpts>`_
480+ object.
481+
482+ A typical configuration using ``socket_keepalive``::
483+
484+ from pymemcache import KeepaliveOpts
485+ from dogpile.cache import make_region
486+
487+ # Using the default keepalive configuration
488+ socket_keepalive = KeepaliveOpts()
489+
490+ region = make_region().configure(
491+ 'dogpile.cache.pymemcache',
492+ expiration_time = 3600,
493+ arguments = {
494+ 'url':["127.0.0.1"],
495+ 'socket_keepalive': socket_keepalive
496+ }
497+ )
498+
499+ .. versionadded:: 1.1.4 - added support for ``socket_keepalive``.
500+
501+ :param enable_retry_client: optional flag to enable retry client
502+ mechanisms to handle failure. Defaults to False. When set to ``True``,
503+ the :paramref:`.PyMemcacheBackend.retry_attempts` parameter must also
504+ be set, along with optional parameters
505+ :paramref:`.PyMemcacheBackend.retry_delay`.
506+ :paramref:`.PyMemcacheBackend.retry_for`,
507+ :paramref:`.PyMemcacheBackend.do_not_retry_for`.
508+
509+ .. seealso::
510+
511+ `<https://pymemcache.readthedocs.io/en/latest/getting_started.html#using-the-built-in-retrying-mechanism>`_ -
512+ in the pymemcache documentation
513+
514+ .. versionadded:: 1.1.4
515+
516+ :param retry_attempts: how many times to attempt an action before
517+ failing. Must be 1 or above. Defaults to None.
518+
519+ .. versionadded:: 1.1.4
520+
521+ :param retry_delay: optional int|float, how many seconds to sleep between
522+ each attempt. Defaults to None.
523+
524+ .. versionadded:: 1.1.4
525+
526+ :param retry_for: optional None|tuple|set|list, what exceptions to
527+ allow retries for. Will allow retries for all exceptions if None.
528+ Example: ``(MemcacheClientError, MemcacheUnexpectedCloseError)``
529+ Accepts any class that is a subclass of Exception. Defaults to None.
530+
531+ .. versionadded:: 1.1.4
532+
533+ :param do_not_retry_for: optional None|tuple|set|list, what
534+ exceptions should be retried. Will not block retries for any Exception if
535+ None. Example: ``(IOError, MemcacheIllegalInputError)``
536+ Accepts any class that is a subclass of Exception. Defaults to None.
537+
538+ .. versionadded:: 1.1.4
539+
540+ """ # noqa E501
493541
494542 def __init__ (self , arguments ):
495543 super ().__init__ (arguments )
496544
497545 self .serde = arguments .get ("serde" , pymemcache .serde .pickle_serde )
498546 self .default_noreply = arguments .get ("default_noreply" , False )
499547 self .tls_context = arguments .get ("tls_context" , None )
548+ self .socket_keepalive = arguments .get ("socket_keepalive" , None )
549+ self .enable_retry_client = arguments .get ("enable_retry_client" , False )
550+ self .retry_attempts = arguments .get ("retry_attempts" , None )
551+ self .retry_delay = arguments .get ("retry_delay" , None )
552+ self .retry_for = arguments .get ("retry_for" , None )
553+ self .do_not_retry_for = arguments .get ("do_not_retry_for" , None )
554+ if (
555+ self .retry_delay is not None
556+ or self .retry_attempts is not None
557+ or self .retry_for is not None
558+ or self .do_not_retry_for is not None
559+ ) and not self .enable_retry_client :
560+ warnings .warn (
561+ "enable_retry_client is not set; retry options "
562+ "will be ignored"
563+ )
500564
501565 def _imports (self ):
502566 global pymemcache
503567 import pymemcache
504568
505569 def _create_client (self ):
506- return pymemcache .client .hash .HashClient (
507- self .url ,
508- serde = self .serde ,
509- default_noreply = self .default_noreply ,
510- tls_context = self .tls_context ,
511- )
570+ _kwargs = {
571+ "serde" : self .serde ,
572+ "default_noreply" : self .default_noreply ,
573+ "tls_context" : self .tls_context ,
574+ }
575+ if self .socket_keepalive is not None :
576+ _kwargs .update ({"socket_keepalive" : self .socket_keepalive })
577+
578+ client = pymemcache .client .hash .HashClient (self .url , ** _kwargs )
579+
580+ if self .enable_retry_client :
581+ return pymemcache .client .retrying .RetryingClient (
582+ client ,
583+ attempts = self .retry_attempts ,
584+ retry_delay = self .retry_delay ,
585+ retry_for = self .retry_for ,
586+ do_not_retry_for = self .do_not_retry_for ,
587+ )
588+
589+ return client
0 commit comments