3636    msg  =  "Could not import cachetools. Did you run 'pip install django-storages[s3]'?" 
3737    raise  ImproperlyConfigured (msg ) from  e 
3838
39+ try :
40+     from  functools  import  cached_property 
41+ except  ImportError :  # python_version<='3.7' 
42+     try :
43+         from  backports .cached_property  import  cached_property 
44+     except  (ImportError , ModuleNotFoundError ) as  e :
45+         msg  =  "Could not import backports.cached_property. Did you run 'pip install django-storages[s3]'?"   # noqa: E501 
46+         raise  ImproperlyConfigured (msg ) from  e 
47+ 
3948try :
4049    import  boto3 .session 
4150    import  botocore 
@@ -379,10 +388,6 @@ def __init__(self, **settings):
379388            else :
380389                self .cloudfront_signer  =  None 
381390
382-         self ._ttl_cache  =  cachetools .cached (
383-             cache = cachetools .TTLCache (maxsize = 2 , ttl = 3600 ), lock = threading .Lock ()
384-         )
385- 
386391    def  get_cloudfront_signer (self , key_id , key ):
387392        cache_key  =  f"{ key_id } { key }  
388393        if  cache_key  not  in self .__class__ ._signers :
@@ -451,6 +456,7 @@ def get_default_settings(self):
451456            "use_threads" : setting ("AWS_S3_USE_THREADS" , True ),
452457            "transfer_config" : setting ("AWS_S3_TRANSFER_CONFIG" , None ),
453458            "client_config" : setting ("AWS_S3_CLIENT_CONFIG" , None ),
459+             "client_ttl" : setting ("AWS_S3_CLIENT_TTL" , 3600 ),
454460        }
455461
456462    def  __getstate__ (self ):
@@ -465,23 +471,27 @@ def __setstate__(self, state):
465471    def  connection (self ):
466472        """ 
467473        Get the (cached) thread-safe boto3 s3 resource. 
468- 
469-         This function has a 1 hour time to live cache for the boto3 resource. 
470-         We want to avoid storing a resource for too long to avoid their memory leak 
471-         ref https://github.com/boto/boto3/issues/1670. 
472474        """ 
473475        return  self ._ttl_cache (self ._create_connection )()
474476
475477    @property  
476478    def  unsigned_connection (self ):
477479        """ 
478480        Get the (cached) thread-safe boto3 s3 resource (unsigned). 
481+         """ 
482+         return  self ._ttl_cache (self ._create_connection )(unsigned = True )
479483
480-         This function has a 1 hour time to live cache for the boto3 resource. 
484+     @cached_property  
485+     def  _ttl_cache (self ):
486+         """ 
487+         This time to live cache is used to periodically recreate boto3 clients. 
481488        We want to avoid storing a resource for too long to avoid their memory leak 
482489        ref https://github.com/boto/boto3/issues/1670. 
483490        """ 
484-         return  self ._ttl_cache (self ._create_connection )(unsigned = True )
491+         return  cachetools .cached (
492+             cache = cachetools .TTLCache (maxsize = 2 , ttl = self .client_ttl ),
493+             lock = threading .Lock (),
494+         )
485495
486496    def  _create_connection (self , * , unsigned = False ):
487497        """ 
0 commit comments