@@ -589,6 +589,33 @@ def TEMPLATES(self):
589589    USE_I18N  =  True 
590590    USE_L10N  =  True 
591591
592+     BUILD_TIME_LIMIT  =  900   # seconds 
593+ 
594+     @property  
595+     def  BUILD_MEMORY_LIMIT (self ):
596+         """ 
597+         Set build memory limit dynamically, if in production, based on system memory. 
598+ 
599+         We do this to avoid having separate build images. This assumes 1 build 
600+         process per server, which will be allowed to consume all available 
601+         memory. 
602+         """ 
603+         # Our normal default 
604+         default_memory_limit  =  "7g" 
605+ 
606+         # Only run on our servers 
607+         if  self .RTD_IS_PRODUCTION :
608+             total_memory , memory_limit  =  self ._get_build_memory_limit ()
609+ 
610+         memory_limit  =  memory_limit  or  default_memory_limit 
611+         log .info (
612+             "Using dynamic build limits." ,
613+             hostname = socket .gethostname (),
614+             memory = memory_limit ,
615+         )
616+         return  memory_limit 
617+ 
618+ 
592619    # Celery 
593620    CELERY_APP_NAME  =  "readthedocs" 
594621    CELERY_ALWAYS_EAGER  =  True 
@@ -605,7 +632,7 @@ def TEMPLATES(self):
605632    # https://github.com/readthedocs/readthedocs.org/issues/12317#issuecomment-3070950434 
606633    # https://docs.celeryq.dev/en/stable/getting-started/backends-and-brokers/redis.html#visibility-timeout 
607634    BROKER_TRANSPORT_OPTIONS  =  {
608-         'visibility_timeout' : 18000 ,  # 5 hours  
635+         'visibility_timeout' : BUILD_TIME_LIMIT   *   1.15 ,  # 15% more than the build time limit  
609636    }
610637
611638    CELERY_DEFAULT_QUEUE  =  "celery" 
@@ -721,7 +748,13 @@ def TEMPLATES(self):
721748    # since we can't read their config file image choice before cloning 
722749    RTD_DOCKER_CLONE_IMAGE  =  RTD_DOCKER_BUILD_SETTINGS ["os" ]["ubuntu-22.04" ]
723750
724-     def  _get_docker_memory_limit (self ):
751+     def  _get_build_memory_limit (self ):
752+         """ 
753+         Return the buld memory limit based on available system memory. 
754+ 
755+         We subtract ~1000Mb for overhead of processes and base system, and set 
756+         the build time as proportional to the memory limit. 
757+         """ 
725758        try :
726759            total_memory  =  int (
727760                subprocess .check_output (
@@ -735,47 +768,6 @@ def _get_docker_memory_limit(self):
735768            # int and raise a ValueError 
736769            log .exception ("Failed to get memory size, using defaults Docker limits." )
737770
738-     # Coefficient used to determine build time limit, as a percentage of total 
739-     # memory. Historical values here were 0.225 to 0.3. 
740-     DOCKER_TIME_LIMIT_COEFF  =  0.25 
741- 
742-     @property  
743-     def  DOCKER_LIMITS (self ):
744-         """ 
745-         Set docker limits dynamically, if in production, based on system memory. 
746- 
747-         We do this to avoid having separate build images. This assumes 1 build 
748-         process per server, which will be allowed to consume all available 
749-         memory. 
750- 
751-         We subtract 750MiB for overhead of processes and base system, and set 
752-         the build time as proportional to the memory limit. 
753-         """ 
754-         # Our normal default 
755-         limits  =  {
756-             "memory" : "2g" ,
757-             "time" : 900 ,
758-         }
759- 
760-         # Only run on our servers 
761-         if  self .RTD_IS_PRODUCTION :
762-             total_memory , memory_limit  =  self ._get_docker_memory_limit ()
763-             if  memory_limit :
764-                 limits  =  {
765-                     "memory" : f"{ memory_limit }  m" ,
766-                     "time" : max (
767-                         limits ["time" ],
768-                         round (total_memory  *  self .DOCKER_TIME_LIMIT_COEFF , - 2 ),
769-                     ),
770-                 }
771-         log .info (
772-             "Using dynamic docker limits." ,
773-             hostname = socket .gethostname (),
774-             memory = limits ["memory" ],
775-             time = limits ["time" ],
776-         )
777-         return  limits 
778- 
779771    # Allauth 
780772    ACCOUNT_ADAPTER  =  "readthedocs.core.adapters.AccountAdapter" 
781773    SOCIALACCOUNT_ADAPTER  =  'readthedocs.core.adapters.SocialAccountAdapter' 
0 commit comments