panda-server-source 0.8.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (375) hide show
  1. panda_server_source-0.8.0.dist-info/METADATA +55 -0
  2. panda_server_source-0.8.0.dist-info/RECORD +375 -0
  3. panda_server_source-0.8.0.dist-info/WHEEL +4 -0
  4. panda_server_source-0.8.0.dist-info/licenses/LICENSE.txt +202 -0
  5. pandajedi/__init__.py +0 -0
  6. pandajedi/jedibrokerage/AtlasAnalJobBroker.py +2343 -0
  7. pandajedi/jedibrokerage/AtlasBrokerUtils.py +1292 -0
  8. pandajedi/jedibrokerage/AtlasProdJobBroker.py +2064 -0
  9. pandajedi/jedibrokerage/AtlasProdTaskBroker.py +629 -0
  10. pandajedi/jedibrokerage/GenJobBroker.py +381 -0
  11. pandajedi/jedibrokerage/JobBrokerBase.py +133 -0
  12. pandajedi/jedibrokerage/TaskBrokerBase.py +15 -0
  13. pandajedi/jedibrokerage/__init__.py +0 -0
  14. pandajedi/jediconfig/__init__.py +0 -0
  15. pandajedi/jediconfig/jedi_config.py +40 -0
  16. pandajedi/jedicore/FactoryBase.py +182 -0
  17. pandajedi/jedicore/Interaction.py +433 -0
  18. pandajedi/jedicore/JediDBProxy.py +56 -0
  19. pandajedi/jedicore/JediDBProxyPool.py +37 -0
  20. pandajedi/jedicore/JediDBSchemaInfo.py +17 -0
  21. pandajedi/jedicore/JediException.py +13 -0
  22. pandajedi/jedicore/JediTaskBuffer.py +984 -0
  23. pandajedi/jedicore/JediTaskBufferInterface.py +50 -0
  24. pandajedi/jedicore/MsgWrapper.py +124 -0
  25. pandajedi/jedicore/ProcessUtils.py +34 -0
  26. pandajedi/jedicore/SiteCandidate.py +90 -0
  27. pandajedi/jedicore/ThreadUtils.py +205 -0
  28. pandajedi/jedicore/__init__.py +0 -0
  29. pandajedi/jediddm/AtlasDDMClient.py +1708 -0
  30. pandajedi/jediddm/DDMClientBase.py +16 -0
  31. pandajedi/jediddm/DDMInterface.py +83 -0
  32. pandajedi/jediddm/GenDDMClient.py +17 -0
  33. pandajedi/jediddm/__init__.py +0 -0
  34. pandajedi/jedidog/AtlasAnalWatchDog.py +648 -0
  35. pandajedi/jedidog/AtlasDataCarouselWatchDog.py +189 -0
  36. pandajedi/jedidog/AtlasDataLocalityUpdaterWatchDog.py +215 -0
  37. pandajedi/jedidog/AtlasProdWatchDog.py +443 -0
  38. pandajedi/jedidog/AtlasQueueFillerWatchDog.py +800 -0
  39. pandajedi/jedidog/AtlasTaskWithholderWatchDog.py +245 -0
  40. pandajedi/jedidog/AtlasWorkflowManagerWatchDog.py +63 -0
  41. pandajedi/jedidog/GenWatchDog.py +21 -0
  42. pandajedi/jedidog/JumboWatchDog.py +147 -0
  43. pandajedi/jedidog/TypicalWatchDogBase.py +122 -0
  44. pandajedi/jedidog/WatchDogBase.py +53 -0
  45. pandajedi/jedidog/__init__.py +0 -0
  46. pandajedi/jediexec/reniceJEDI.py +25 -0
  47. pandajedi/jedigen/AtlasTaskGenerator.py +110 -0
  48. pandajedi/jedigen/TaskGeneratorBase.py +15 -0
  49. pandajedi/jedigen/__init__.py +0 -0
  50. pandajedi/jedimsgprocessor/__init__.py +0 -0
  51. pandajedi/jedimsgprocessor/ai_parameter_adjuster_msg_processor +71 -0
  52. pandajedi/jedimsgprocessor/atlas_idds_msg_processor.py +66 -0
  53. pandajedi/jedimsgprocessor/base_msg_processor.py +33 -0
  54. pandajedi/jedimsgprocessor/forwarding_msg_processor.py +29 -0
  55. pandajedi/jedimsgprocessor/hpo_msg_processor.py +93 -0
  56. pandajedi/jedimsgprocessor/jedi_contents_feeder_msg_processor.py +63 -0
  57. pandajedi/jedimsgprocessor/jedi_job_generator_msg_processor.py +185 -0
  58. pandajedi/jedimsgprocessor/jedi_post_processor_msg_processor.py +82 -0
  59. pandajedi/jedimsgprocessor/kafka_msg_processor.py +44 -0
  60. pandajedi/jedimsgprocessor/panda_callback_msg_processor.py +182 -0
  61. pandajedi/jedimsgprocessor/panda_to_jedi_msg_processor.py +74 -0
  62. pandajedi/jedimsgprocessor/processing_msg_processor.py +134 -0
  63. pandajedi/jedimsgprocessor/status_report_msg_processor.py +129 -0
  64. pandajedi/jedimsgprocessor/tape_carousel_msg_processor.py +118 -0
  65. pandajedi/jedimsgprocessor/workflow_manager_msg_processor.py +89 -0
  66. pandajedi/jediorder/ContentsFeeder.py +785 -0
  67. pandajedi/jediorder/JediDaemon.py +27 -0
  68. pandajedi/jediorder/JediKnight.py +55 -0
  69. pandajedi/jediorder/JediMaster.py +238 -0
  70. pandajedi/jediorder/JediMsgProcessor.py +32 -0
  71. pandajedi/jediorder/JobBroker.py +33 -0
  72. pandajedi/jediorder/JobGenerator.py +2763 -0
  73. pandajedi/jediorder/JobSplitter.py +308 -0
  74. pandajedi/jediorder/JobThrottler.py +28 -0
  75. pandajedi/jediorder/PostProcessor.py +166 -0
  76. pandajedi/jediorder/TaskBroker.py +268 -0
  77. pandajedi/jediorder/TaskCommando.py +334 -0
  78. pandajedi/jediorder/TaskGenerator.py +17 -0
  79. pandajedi/jediorder/TaskRefiner.py +611 -0
  80. pandajedi/jediorder/TaskSetupper.py +17 -0
  81. pandajedi/jediorder/WatchDog.py +79 -0
  82. pandajedi/jediorder/__init__.py +0 -0
  83. pandajedi/jedipprocess/AtlasAnalPostProcessor.py +404 -0
  84. pandajedi/jedipprocess/AtlasPostProcessorUtils.py +50 -0
  85. pandajedi/jedipprocess/AtlasProdPostProcessor.py +178 -0
  86. pandajedi/jedipprocess/GenPostProcessor.py +35 -0
  87. pandajedi/jedipprocess/MailTemplates.py +185 -0
  88. pandajedi/jedipprocess/PostProcessorBase.py +269 -0
  89. pandajedi/jedipprocess/__init__.py +0 -0
  90. pandajedi/jedirefine/AtlasAnalTaskRefiner.py +259 -0
  91. pandajedi/jedirefine/AtlasProdTaskRefiner.py +162 -0
  92. pandajedi/jedirefine/GenTaskRefiner.py +61 -0
  93. pandajedi/jedirefine/RefinerUtils.py +154 -0
  94. pandajedi/jedirefine/TaskRefinerBase.py +996 -0
  95. pandajedi/jedirefine/__init__.py +0 -0
  96. pandajedi/jedisetup/AtlasTaskSetupper.py +309 -0
  97. pandajedi/jedisetup/GenTaskSetupper.py +16 -0
  98. pandajedi/jedisetup/SimpleTaskSetupper.py +152 -0
  99. pandajedi/jedisetup/TaskSetupperBase.py +15 -0
  100. pandajedi/jedisetup/__init__.py +0 -0
  101. pandajedi/jeditest/SchemaChecker.py +41 -0
  102. pandajedi/jeditest/addContWoSoTask.py +54 -0
  103. pandajedi/jeditest/addDataCarouselRequest.py +47 -0
  104. pandajedi/jeditest/addEventServiceTask.py +101 -0
  105. pandajedi/jeditest/addHpoTask.py +81 -0
  106. pandajedi/jeditest/addIDDSStageInRequest.py +56 -0
  107. pandajedi/jeditest/addNonAtlasTask.py +71 -0
  108. pandajedi/jeditest/addNonAtlasTaskEnc.py +64 -0
  109. pandajedi/jeditest/addTestTask.py +124 -0
  110. pandajedi/jeditest/addTestTaskParamToDEFT.py +70 -0
  111. pandajedi/jeditest/addTestTaskWithMerger.py +97 -0
  112. pandajedi/jeditest/brokerTest.py +78 -0
  113. pandajedi/jeditest/cancelDataCarouselRequest.py +35 -0
  114. pandajedi/jeditest/contentsFeederTest.py +28 -0
  115. pandajedi/jeditest/contentsFeederTestWithTask.py +18 -0
  116. pandajedi/jeditest/ddmTest.py +4 -0
  117. pandajedi/jeditest/jobGenForOneTask.py +38 -0
  118. pandajedi/jeditest/jobGeneratorTest.py +43 -0
  119. pandajedi/jeditest/jobSplitterTest.py +104 -0
  120. pandajedi/jeditest/jobThrottlerTest.py +22 -0
  121. pandajedi/jeditest/msgProcessorTest.py +9 -0
  122. pandajedi/jeditest/postProcessorTest.py +18 -0
  123. pandajedi/jeditest/resubmitDataCarouselRequest.py +35 -0
  124. pandajedi/jeditest/resubmitTaskParam.py +20 -0
  125. pandajedi/jeditest/taskBrokerTest.py +22 -0
  126. pandajedi/jeditest/taskBrokerTestWithTask.py +38 -0
  127. pandajedi/jeditest/taskBufferTest.py +5 -0
  128. pandajedi/jeditest/taskCommandoTest.py +28 -0
  129. pandajedi/jeditest/taskRefinerTest.py +30 -0
  130. pandajedi/jeditest/testOneTaskToRefine.py +49 -0
  131. pandajedi/jeditest/testOneTaskToTaskBroker.py +42 -0
  132. pandajedi/jeditest/testPandaDDMMap.py +62 -0
  133. pandajedi/jeditest/updateDataCarouselRequestParams.py +50 -0
  134. pandajedi/jeditest/watchDogTest.py +25 -0
  135. pandajedi/jeditest/workQueueTest.py +22 -0
  136. pandajedi/jedithrottle/AtlasAnalJobThrottler.py +19 -0
  137. pandajedi/jedithrottle/AtlasProdJobThrottler.py +18 -0
  138. pandajedi/jedithrottle/GenJobThrottler.py +26 -0
  139. pandajedi/jedithrottle/JobThrottlerBase.py +496 -0
  140. pandajedi/jedithrottle/__init__.py +0 -0
  141. pandaserver/__init__.py +0 -0
  142. pandaserver/api/__init__.py +0 -0
  143. pandaserver/api/v1/__init__.py +0 -0
  144. pandaserver/api/v1/common.py +339 -0
  145. pandaserver/api/v1/credential_management_api.py +372 -0
  146. pandaserver/api/v1/data_carousel_api.py +264 -0
  147. pandaserver/api/v1/event_api.py +269 -0
  148. pandaserver/api/v1/file_server_api.py +942 -0
  149. pandaserver/api/v1/harvester_api.py +445 -0
  150. pandaserver/api/v1/http_client.py +166 -0
  151. pandaserver/api/v1/idds_api.py +180 -0
  152. pandaserver/api/v1/job_api.py +463 -0
  153. pandaserver/api/v1/metaconfig_api.py +122 -0
  154. pandaserver/api/v1/pilot_api.py +895 -0
  155. pandaserver/api/v1/statistics_api.py +207 -0
  156. pandaserver/api/v1/system_api.py +186 -0
  157. pandaserver/api/v1/task_api.py +1520 -0
  158. pandaserver/api/v1/tests/__init__.py +0 -0
  159. pandaserver/api/v1/tests/credential_management_api_tests.py +116 -0
  160. pandaserver/api/v1/tests/data_carousel_api_tests.py +82 -0
  161. pandaserver/api/v1/tests/harvester_api_tests.py +188 -0
  162. pandaserver/api/v1/tests/idds_api_tests.py +45 -0
  163. pandaserver/api/v1/tests/job_api_tests.py +112 -0
  164. pandaserver/api/v1/tests/pilot_api_tests.py +154 -0
  165. pandaserver/api/v1/tests/statistics_api_tests.py +104 -0
  166. pandaserver/api/v1/tests/system_api_tests.py +58 -0
  167. pandaserver/api/v1/tests/task_api_tests.py +590 -0
  168. pandaserver/api/v1/version.py +2 -0
  169. pandaserver/api/v1/workflow_api.py +136 -0
  170. pandaserver/brokerage/SiteMapper.py +406 -0
  171. pandaserver/brokerage/__init__.py +0 -0
  172. pandaserver/brokerage/broker.py +272 -0
  173. pandaserver/config/__init__.py +0 -0
  174. pandaserver/config/config_utils.py +15 -0
  175. pandaserver/config/daemon_config.py +29 -0
  176. pandaserver/config/mcp_config.py +38 -0
  177. pandaserver/config/panda_config.py +233 -0
  178. pandaserver/configurator/Carbon.py +65 -0
  179. pandaserver/configurator/Configurator.py +908 -0
  180. pandaserver/configurator/__init__.py +0 -0
  181. pandaserver/configurator/aux.py +73 -0
  182. pandaserver/daemons/__init__.py +0 -0
  183. pandaserver/daemons/master.py +110 -0
  184. pandaserver/daemons/master_systemd.py +79 -0
  185. pandaserver/daemons/scripts/__init__.py +0 -0
  186. pandaserver/daemons/scripts/add_main.py +264 -0
  187. pandaserver/daemons/scripts/add_sub.py +221 -0
  188. pandaserver/daemons/scripts/cache_pilots.py +47 -0
  189. pandaserver/daemons/scripts/cache_schedconfig.py +286 -0
  190. pandaserver/daemons/scripts/carbon.py +50 -0
  191. pandaserver/daemons/scripts/configurator.py +94 -0
  192. pandaserver/daemons/scripts/copyArchive.py +1387 -0
  193. pandaserver/daemons/scripts/datasetManager.py +1154 -0
  194. pandaserver/daemons/scripts/dummy_test.py +25 -0
  195. pandaserver/daemons/scripts/evpPD2P.py +144 -0
  196. pandaserver/daemons/scripts/hs_scrapers.py +264 -0
  197. pandaserver/daemons/scripts/metric_collector.py +927 -0
  198. pandaserver/daemons/scripts/panda_activeusers_query.py +80 -0
  199. pandaserver/daemons/scripts/pilotStreaming.py +109 -0
  200. pandaserver/daemons/scripts/process_workflow_files_daemon.py +166 -0
  201. pandaserver/daemons/scripts/recover_lost_files_daemon.py +177 -0
  202. pandaserver/daemons/scripts/task_evaluator.py +405 -0
  203. pandaserver/daemons/scripts/tmpwatch.py +70 -0
  204. pandaserver/daemons/scripts/worker_synchronization.py +97 -0
  205. pandaserver/daemons/utils.py +753 -0
  206. pandaserver/dataservice/DataServiceUtils.py +323 -0
  207. pandaserver/dataservice/ErrorCode.py +25 -0
  208. pandaserver/dataservice/RecoverLostFilesCore.py +322 -0
  209. pandaserver/dataservice/__init__.py +0 -0
  210. pandaserver/dataservice/activator.py +79 -0
  211. pandaserver/dataservice/adder_atlas_plugin.py +1106 -0
  212. pandaserver/dataservice/adder_dummy_plugin.py +31 -0
  213. pandaserver/dataservice/adder_gen.py +954 -0
  214. pandaserver/dataservice/adder_plugin_base.py +27 -0
  215. pandaserver/dataservice/adder_result.py +75 -0
  216. pandaserver/dataservice/adder_simple_plugin.py +160 -0
  217. pandaserver/dataservice/closer.py +247 -0
  218. pandaserver/dataservice/closer_atlas_plugin.py +90 -0
  219. pandaserver/dataservice/ddm.py +1381 -0
  220. pandaserver/dataservice/ddm_handler.py +95 -0
  221. pandaserver/dataservice/dyn_data_distributer.py +824 -0
  222. pandaserver/dataservice/event_lookup_client_ei.py +77 -0
  223. pandaserver/dataservice/event_picker.py +268 -0
  224. pandaserver/dataservice/finisher.py +194 -0
  225. pandaserver/dataservice/setupper.py +225 -0
  226. pandaserver/dataservice/setupper_atlas_plugin.py +1851 -0
  227. pandaserver/dataservice/setupper_dummy_plugin.py +47 -0
  228. pandaserver/dataservice/setupper_plugin_base.py +67 -0
  229. pandaserver/jobdispatcher/DispatcherUtils.py +35 -0
  230. pandaserver/jobdispatcher/ErrorCode.py +19 -0
  231. pandaserver/jobdispatcher/JobDispatcher.py +1625 -0
  232. pandaserver/jobdispatcher/Protocol.py +443 -0
  233. pandaserver/jobdispatcher/Watcher.py +186 -0
  234. pandaserver/jobdispatcher/__init__.py +0 -0
  235. pandaserver/pandamcp/__init__.py +0 -0
  236. pandaserver/pandamcp/mcp_main.py +56 -0
  237. pandaserver/pandamcp/mcp_test_client.py +95 -0
  238. pandaserver/pandamcp/mcp_utils.py +74 -0
  239. pandaserver/proxycache/__init__.py +0 -0
  240. pandaserver/proxycache/panda_proxy_cache.py +240 -0
  241. pandaserver/proxycache/token_cache.py +141 -0
  242. pandaserver/server/.gacl +6 -0
  243. pandaserver/server/panda.py +539 -0
  244. pandaserver/srvcore/CoreUtils.py +572 -0
  245. pandaserver/srvcore/MailUtils.py +106 -0
  246. pandaserver/srvcore/__init__.py +0 -0
  247. pandaserver/srvcore/allowed_methods.py +100 -0
  248. pandaserver/srvcore/oidc_utils.py +152 -0
  249. pandaserver/srvcore/panda_request.py +196 -0
  250. pandaserver/srvcore/srv_msg_utils.py +42 -0
  251. pandaserver/taskbuffer/ConBridge.py +513 -0
  252. pandaserver/taskbuffer/DBProxyPool.py +95 -0
  253. pandaserver/taskbuffer/DataCarousel.py +3053 -0
  254. pandaserver/taskbuffer/DatasetSpec.py +137 -0
  255. pandaserver/taskbuffer/DdmSpec.py +201 -0
  256. pandaserver/taskbuffer/ErrorCode.py +87 -0
  257. pandaserver/taskbuffer/EventServiceUtils.py +396 -0
  258. pandaserver/taskbuffer/FileSpec.py +290 -0
  259. pandaserver/taskbuffer/GlobalShares.py +244 -0
  260. pandaserver/taskbuffer/HarvesterMetricsSpec.py +92 -0
  261. pandaserver/taskbuffer/Initializer.py +82 -0
  262. pandaserver/taskbuffer/InputChunk.py +1080 -0
  263. pandaserver/taskbuffer/JediCacheSpec.py +57 -0
  264. pandaserver/taskbuffer/JediDatasetSpec.py +588 -0
  265. pandaserver/taskbuffer/JediFileSpec.py +242 -0
  266. pandaserver/taskbuffer/JediTaskSpec.py +1687 -0
  267. pandaserver/taskbuffer/JobSpec.py +1006 -0
  268. pandaserver/taskbuffer/JobUtils.py +232 -0
  269. pandaserver/taskbuffer/NucleusSpec.py +116 -0
  270. pandaserver/taskbuffer/OraDBProxy.py +174 -0
  271. pandaserver/taskbuffer/PanDAMsgProcessor.py +8 -0
  272. pandaserver/taskbuffer/PandaDBSchemaInfo.py +18 -0
  273. pandaserver/taskbuffer/ParseJobXML.py +350 -0
  274. pandaserver/taskbuffer/PickleFileSpec.py +18 -0
  275. pandaserver/taskbuffer/PickleJobSpec.py +25 -0
  276. pandaserver/taskbuffer/PrioUtil.py +40 -0
  277. pandaserver/taskbuffer/ProcessGroups.py +111 -0
  278. pandaserver/taskbuffer/ResourceSpec.py +175 -0
  279. pandaserver/taskbuffer/SQLDumper.py +37 -0
  280. pandaserver/taskbuffer/SQLManager.py +60 -0
  281. pandaserver/taskbuffer/SiteSpec.py +304 -0
  282. pandaserver/taskbuffer/SupErrors.py +10 -0
  283. pandaserver/taskbuffer/TaskBuffer.py +2882 -0
  284. pandaserver/taskbuffer/TaskBufferInterface.py +163 -0
  285. pandaserver/taskbuffer/Utils.py +848 -0
  286. pandaserver/taskbuffer/WorkQueue.py +227 -0
  287. pandaserver/taskbuffer/WorkQueueMapper.py +203 -0
  288. pandaserver/taskbuffer/WorkerSpec.py +143 -0
  289. pandaserver/taskbuffer/WrappedCursor.py +487 -0
  290. pandaserver/taskbuffer/WrappedPickle.py +88 -0
  291. pandaserver/taskbuffer/WrappedPostgresConn.py +24 -0
  292. pandaserver/taskbuffer/__init__.py +0 -0
  293. pandaserver/taskbuffer/db_proxy_mods/OraDBProxy_structure.png +0 -0
  294. pandaserver/taskbuffer/db_proxy_mods/__init__.py +7 -0
  295. pandaserver/taskbuffer/db_proxy_mods/base_module.py +841 -0
  296. pandaserver/taskbuffer/db_proxy_mods/data_carousel_module.py +772 -0
  297. pandaserver/taskbuffer/db_proxy_mods/entity_module.py +3804 -0
  298. pandaserver/taskbuffer/db_proxy_mods/job_complex_module.py +5661 -0
  299. pandaserver/taskbuffer/db_proxy_mods/job_standalone_module.py +2640 -0
  300. pandaserver/taskbuffer/db_proxy_mods/metrics_module.py +874 -0
  301. pandaserver/taskbuffer/db_proxy_mods/misc_standalone_module.py +4272 -0
  302. pandaserver/taskbuffer/db_proxy_mods/task_complex_module.py +6172 -0
  303. pandaserver/taskbuffer/db_proxy_mods/task_event_module.py +4953 -0
  304. pandaserver/taskbuffer/db_proxy_mods/task_standalone_module.py +4999 -0
  305. pandaserver/taskbuffer/db_proxy_mods/task_utils_module.py +2063 -0
  306. pandaserver/taskbuffer/db_proxy_mods/worker_module.py +1944 -0
  307. pandaserver/taskbuffer/db_proxy_mods/workflow_module.py +832 -0
  308. pandaserver/taskbuffer/retryModule.py +552 -0
  309. pandaserver/taskbuffer/task_split_rules.py +308 -0
  310. pandaserver/taskbuffer/workflow_processor.py +249 -0
  311. pandaserver/taskbuffer/wrapped_oracle_conn.py +18 -0
  312. pandaserver/test/SchemaChecker.py +40 -0
  313. pandaserver/test/__init__.py +0 -0
  314. pandaserver/test/banUser.py +43 -0
  315. pandaserver/test/boostPrio.py +19 -0
  316. pandaserver/test/boostUser.py +35 -0
  317. pandaserver/test/callbackDDM.py +11 -0
  318. pandaserver/test/daod_on_demand.py +95 -0
  319. pandaserver/test/finishJob.py +184 -0
  320. pandaserver/test/finishTaskJEDI.py +11 -0
  321. pandaserver/test/getJobs.py +53 -0
  322. pandaserver/test/killJob.py +79 -0
  323. pandaserver/test/killJobLowPrio.py +99 -0
  324. pandaserver/test/killJobsInTask.py +56 -0
  325. pandaserver/test/killTask.py +80 -0
  326. pandaserver/test/killTaskJEDI.py +11 -0
  327. pandaserver/test/killUser.py +83 -0
  328. pandaserver/test/lsst/README.txt +7 -0
  329. pandaserver/test/lsst/lsstSubmit.py +139 -0
  330. pandaserver/test/lsst/lsstSubmitMERGEtest.py +141 -0
  331. pandaserver/test/lsst/lsstSubmitPhosim332.py +53 -0
  332. pandaserver/test/lsst/prepare-client-tarball-from-bigpanda-server.sh +41 -0
  333. pandaserver/test/reassignJobs.py +17 -0
  334. pandaserver/test/reassignSite.py +82 -0
  335. pandaserver/test/reassignTask.py +117 -0
  336. pandaserver/test/reassignWaiting.py +39 -0
  337. pandaserver/test/recoverLostFiles.py +7 -0
  338. pandaserver/test/reloadInputDS.py +51 -0
  339. pandaserver/test/sendCommandToJob.py +26 -0
  340. pandaserver/test/setDebugMode.py +38 -0
  341. pandaserver/test/setPriority.py +28 -0
  342. pandaserver/test/testEvgen.py +60 -0
  343. pandaserver/test/testEvgen17.py +58 -0
  344. pandaserver/test/testG4sim.py +81 -0
  345. pandaserver/test/testG4sim17.py +90 -0
  346. pandaserver/test/testGlobalShares.py +131 -0
  347. pandaserver/test/testReco.py +103 -0
  348. pandaserver/test/testSimulReco14.py +98 -0
  349. pandaserver/test/testSiteMap.py +26 -0
  350. pandaserver/test/testUpdateWorkerPilotStatus.py +9 -0
  351. pandaserver/userinterface/Client.py +1686 -0
  352. pandaserver/userinterface/UserIF.py +1799 -0
  353. pandaserver/userinterface/__init__.py +0 -0
  354. pandaserver/workflow/__init__.py +0 -0
  355. pandaserver/workflow/data_handler_plugins/base_data_handler.py +48 -0
  356. pandaserver/workflow/data_handler_plugins/ddm_collection_data_handler.py +100 -0
  357. pandaserver/workflow/data_handler_plugins/panda_task_data_handler.py +140 -0
  358. pandaserver/workflow/pcwl_test.py +122 -0
  359. pandaserver/workflow/pcwl_utils.py +384 -0
  360. pandaserver/workflow/psnakemake_container.json +68 -0
  361. pandaserver/workflow/psnakemake_task.json +62 -0
  362. pandaserver/workflow/psnakemake_test.py +60 -0
  363. pandaserver/workflow/snakeparser/__init__.py +3 -0
  364. pandaserver/workflow/snakeparser/extensions.py +74 -0
  365. pandaserver/workflow/snakeparser/log.py +53 -0
  366. pandaserver/workflow/snakeparser/names.py +3 -0
  367. pandaserver/workflow/snakeparser/parser.py +332 -0
  368. pandaserver/workflow/snakeparser/utils.py +29 -0
  369. pandaserver/workflow/step_handler_plugins/base_step_handler.py +85 -0
  370. pandaserver/workflow/step_handler_plugins/panda_task_step_handler.py +280 -0
  371. pandaserver/workflow/workflow_base.py +531 -0
  372. pandaserver/workflow/workflow_core.py +1974 -0
  373. pandaserver/workflow/workflow_core_smoketest.py +388 -0
  374. pandaserver/workflow/workflow_parser.py +222 -0
  375. pandaserver/workflow/workflow_utils.py +1047 -0
@@ -0,0 +1,496 @@
1
+ from pandajedi.jedicore import Interaction
2
+ from pandajedi.jedicore.MsgWrapper import MsgWrapper
3
+
4
+ # throttle level
5
+ THR_LEVEL5 = 5
6
+
7
+ LEVEL_None = 0 # There is no configuration defined
8
+ LEVEL_GS = 1 # There is a configuration defined at global share level
9
+ LEVEL_MS = 2 # There is a configuration defined at MCORE/SCORE level
10
+ LEVEL_RT = 3 # There is a configuration defined at resource type level
11
+
12
+ NQUEUELIMIT = "NQUEUELIMIT"
13
+ NRUNNINGCAP = "NRUNNINGCAP"
14
+ NQUEUECAP = "NQUEUECAP"
15
+
16
+ # workqueues that do not work at resource type level.
17
+ # E.g. event service is a special case, since MCORE tasks generate SCORE jobs. Therefore we can't work at
18
+ # resource type level and need to go to the global level, in order to avoid over-generating jobs
19
+ non_rt_wqs = ["eventservice"]
20
+
21
+
22
+ # base class for job throttle
23
+ class JobThrottlerBase(object):
24
+ def __init__(self, taskBufferIF):
25
+ self.taskBufferIF = taskBufferIF
26
+ # returns
27
+ self.retTmpError = self.SC_FAILED, True
28
+ self.retThrottled = self.SC_SUCCEEDED, True
29
+ self.retUnThrottled = self.SC_SUCCEEDED, False
30
+ self.retMergeUnThr = self.SC_SUCCEEDED, THR_LEVEL5
31
+ # limit
32
+ self.refresh()
33
+ self.msgType = "jobthrottler"
34
+ self.comp_name = "base_job_throttler"
35
+ self.app = "jedi"
36
+
37
+ # refresh
38
+ def refresh(self):
39
+ self.maxNumJobs = None
40
+ self.minPriority = None
41
+ self.underNqLimit = False
42
+ self.siteMapper = self.taskBufferIF.get_site_mapper()
43
+
44
+ # set maximum number of jobs to be submitted
45
+ def setMaxNumJobs(self, maxNumJobs):
46
+ self.maxNumJobs = maxNumJobs
47
+
48
+ # set min priority of jobs to be submitted
49
+ def setMinPriority(self, minPriority):
50
+ self.minPriority = minPriority
51
+
52
+ # check throttle level
53
+ def mergeThrottled(self, thrLevel):
54
+ # un-leveled flag
55
+ if thrLevel in [True, False]:
56
+ return thrLevel
57
+ return thrLevel > THR_LEVEL5
58
+
59
+ # check if lack of jobs
60
+ def lackOfJobs(self):
61
+ return self.underNqLimit
62
+
63
+ # not enough jobs are queued
64
+ def notEnoughJobsQueued(self):
65
+ self.underNqLimit = True
66
+
67
+ def __getConfiguration(self, vo, queue_name, resource_name):
68
+ # component name
69
+ comp_name = self.comp_name
70
+ app = self.app
71
+
72
+ # Avoid memory fragmentation
73
+ resource_ms = None
74
+ if resource_name.startswith("MCORE"):
75
+ resource_ms = "MCORE"
76
+ elif resource_name.startswith("SCORE"):
77
+ resource_ms = "SCORE"
78
+
79
+ # Read the WQ config values from the DB
80
+ config_map = {
81
+ NQUEUELIMIT: {"value": None, "level": LEVEL_None, "key": None},
82
+ NRUNNINGCAP: {"value": None, "level": LEVEL_None, "key": None},
83
+ NQUEUECAP: {"value": None, "level": LEVEL_None, "key": None},
84
+ }
85
+
86
+ for tag in (NQUEUELIMIT, NRUNNINGCAP, NQUEUECAP):
87
+ # 1. try to get a wq + resource_type specific limit
88
+ key_name = f"{tag}_{queue_name}_{resource_name}"
89
+ value = self.taskBufferIF.getConfigValue(comp_name, key_name, app, vo)
90
+ if value:
91
+ config_map[tag] = {"value": value, "level": LEVEL_RT, "key": key_name}
92
+ continue
93
+
94
+ # 2. try to get a wq + MCORE/SCORE specific limit
95
+ key_name = f"{tag}_{queue_name}_{resource_ms}*"
96
+ value = self.taskBufferIF.getConfigValue(comp_name, key_name, app, vo)
97
+ if value:
98
+ config_map[tag] = {"value": value, "level": LEVEL_MS, "key": key_name}
99
+ continue
100
+
101
+ # 3. try to get a wq specific limit
102
+ key_name = f"{tag}_{queue_name}"
103
+ value = self.taskBufferIF.getConfigValue(comp_name, key_name, app, vo)
104
+ if value:
105
+ config_map[tag] = {"value": value, "level": LEVEL_GS, "key": key_name}
106
+
107
+ return config_map
108
+
109
+ def __prepareJobStats(self, work_queue, resource_name, config_map):
110
+ """
111
+ Calculates the jobs at resource level (SCORE or MCORE) and in total.
112
+
113
+ :param work_queue: work_queue object
114
+ :param resource_name: resource name, e.g. SCORE, MCORE, SCORE_HIMEM, MCORE_HIMEM
115
+ :return: resource_level, nRunning, nRunning_level, nNotRun, nNotRun_level, nDefine, nDefine_level, nWaiting, nWaiting_level
116
+ """
117
+ # SCORE vs MCORE
118
+ if resource_name.startswith("MCORE"):
119
+ ms = "MCORE"
120
+ else:
121
+ ms = "SCORE"
122
+
123
+ # get job statistics
124
+ status, wq_stats = self.taskBufferIF.getJobStatisticsByResourceType(work_queue)
125
+ if not status:
126
+ raise RuntimeError("failed to get job statistics")
127
+
128
+ # get the number of standby jobs which is used as the number of running jobs
129
+ standby_num_static, standby_num_static_dynamic = self.taskBufferIF.getNumMapForStandbyJobs_JEDI(work_queue)
130
+
131
+ # add running if the original stat doesn't have running and standby jobs are required
132
+ if "running" not in wq_stats and (len(standby_num_static) > 0 or len(standby_num_static_dynamic) > 0):
133
+ wq_stats["running"] = {}
134
+
135
+ # add dummy to subtract # of starting for dynamic number of standby jobs
136
+ if len(standby_num_static_dynamic) > 0:
137
+ wq_stats["dummy"] = standby_num_static_dynamic
138
+
139
+ # Count number of jobs in each status
140
+ # We want to generate one value for the total, one value for the relevant MCORE/SCORE level
141
+ # and one value for the full global share
142
+ nRunning_rt, nRunning_ms, nRunning_gs = 0, 0, 0
143
+ nNotRun_rt, nNotRun_ms, nNotRun_gs = 0, 0, 0
144
+ nDefine_rt, nDefine_ms, nDefine_gs = 0, 0, 0
145
+ nWaiting_rt, nWaiting_gs = 0, 0
146
+
147
+ for status in wq_stats:
148
+ nJobs_rt, nJobs_ms, nJobs_gs = 0, 0, 0
149
+ stats_list = list(wq_stats[status].items())
150
+ # take into account the number of standby jobs
151
+ if status == "running":
152
+ stats_list += list(standby_num_static.items())
153
+ stats_list += list(standby_num_static_dynamic.items())
154
+ for resource_type, count in stats_list:
155
+ if resource_type == resource_name:
156
+ nJobs_rt = count
157
+ if resource_type.startswith(ms):
158
+ nJobs_ms += count
159
+ nJobs_gs += count
160
+
161
+ if status == "running":
162
+ nRunning_rt = nJobs_rt
163
+ nRunning_ms = nJobs_ms
164
+ nRunning_gs = nJobs_gs
165
+ elif status == "defined":
166
+ nDefine_rt = nJobs_rt
167
+ nDefine_ms = nJobs_ms
168
+ nDefine_gs = nJobs_gs
169
+ elif status == "waiting":
170
+ nWaiting_rt = nJobs_rt
171
+ nWaiting_gs = nJobs_gs
172
+ elif status in ["assigned", "activated", "starting"]:
173
+ nNotRun_rt += nJobs_rt
174
+ nNotRun_ms += nJobs_ms
175
+ nNotRun_gs += nJobs_gs
176
+ elif status == "dummy":
177
+ nNotRun_rt -= nJobs_rt
178
+ nNotRun_ms -= nJobs_ms
179
+ nNotRun_gs -= nJobs_gs
180
+
181
+ # Get the job stats at the same level as the configured parameters
182
+ # nRunning is compared with the nRunningCap
183
+ if config_map[NRUNNINGCAP]["level"] == LEVEL_GS:
184
+ nRunning_runningcap = nRunning_gs
185
+ elif config_map[NRUNNINGCAP]["level"] == LEVEL_MS:
186
+ nRunning_runningcap = nRunning_ms
187
+ else:
188
+ nRunning_runningcap = nRunning_rt
189
+
190
+ # nNotRun and nDefine are compared with the nQueueLimit
191
+ if config_map[NQUEUELIMIT]["level"] == LEVEL_GS:
192
+ nNotRun_queuelimit = nNotRun_gs
193
+ nDefine_queuelimit = nDefine_gs
194
+ elif config_map[NQUEUELIMIT]["level"] == LEVEL_MS:
195
+ nNotRun_queuelimit = nNotRun_ms
196
+ nDefine_queuelimit = nDefine_ms
197
+ else:
198
+ nNotRun_queuelimit = nNotRun_rt
199
+ nDefine_queuelimit = nDefine_rt
200
+
201
+ # nNotRun and nDefine are compared with the nQueueCap
202
+ if config_map[NQUEUECAP]["level"] == LEVEL_GS:
203
+ nNotRun_queuecap = nNotRun_gs
204
+ nDefine_queuecap = nDefine_gs
205
+ elif config_map[NQUEUECAP]["level"] == LEVEL_MS:
206
+ nNotRun_queuecap = nNotRun_ms
207
+ nDefine_queuecap = nDefine_ms
208
+ else:
209
+ nNotRun_queuecap = nNotRun_rt
210
+ nDefine_queuecap = nDefine_rt
211
+
212
+ return_map = {
213
+ "nRunning_rt": nRunning_rt,
214
+ "nRunning_gs": nRunning_gs,
215
+ "nRunning_runningcap": nRunning_runningcap,
216
+ "nNotRun_rt": nNotRun_rt,
217
+ "nNotRun_gs": nNotRun_gs,
218
+ "nNotRun_queuelimit": nNotRun_queuelimit,
219
+ "nNotRun_queuecap": nNotRun_queuecap,
220
+ "nDefine_rt": nDefine_rt,
221
+ "nDefine_gs": nDefine_gs,
222
+ "nDefine_queuelimit": nDefine_queuelimit,
223
+ "nDefine_queuecap": nDefine_queuecap,
224
+ "nWaiting_rt": nWaiting_rt,
225
+ "nWaiting_gs": nWaiting_gs,
226
+ }
227
+
228
+ return return_map
229
+
230
+ # check if throttled
231
+ def toBeThrottledBase(self, vo, prodSourceLabel, cloud_name, workQueue, resource_name, logger):
232
+ workqueue_id = workQueue.getID()
233
+ workqueue_name = "_".join(workQueue.queue_name.split(" "))
234
+
235
+ # params
236
+ nBunch = 4
237
+ work_shortage = self.taskBufferIF.getConfigValue("core", "WORK_SHORTAGE", self.app, vo)
238
+ if work_shortage is True:
239
+ threshold = self.taskBufferIF.getConfigValue(self.comp_name, "THROTTLE_THRESHOLD_FOR_WORK_SHORTAGE", self.app, vo)
240
+ else:
241
+ threshold = self.taskBufferIF.getConfigValue(self.comp_name, "THROTTLE_THRESHOLD", self.app, vo)
242
+ if threshold is None:
243
+ threshold = 2.0
244
+ nJobsInBunchMax = 600
245
+ nJobsInBunchMin = 500
246
+ minTotalWalltime = 50 * 1000 * 1000
247
+ nWaitingLimit = 4
248
+ nWaitingBunchLimit = 2
249
+ nParallel = 2
250
+ nParallelCap = 5
251
+
252
+ # make logger
253
+ tmp_log = MsgWrapper(logger)
254
+ msg_header = f"{vo}:{prodSourceLabel} cloud={cloud_name} queue={workqueue_name} resource_type={resource_name}:"
255
+ tmp_log.debug(f"{msg_header} start workqueue_id={workqueue_id} threshold={threshold}")
256
+
257
+ # check if unthrottled
258
+ if not workQueue.throttled:
259
+ msg_body = "PASS unthrottled since GS_throttled is False"
260
+ tmp_log.info(msg_header + " " + msg_body)
261
+ return self.retUnThrottled
262
+
263
+ # get central configuration values
264
+ config_map = self.__getConfiguration(vo, workQueue.queue_name, resource_name)
265
+ configQueueLimit = config_map[NQUEUELIMIT]["value"]
266
+ configQueueLimitKey = config_map[NQUEUELIMIT]["key"]
267
+ configQueueCap = config_map[NQUEUECAP]["value"]
268
+ configQueueCapKey = config_map[NQUEUECAP]["key"]
269
+ configRunningCap = config_map[NRUNNINGCAP]["value"]
270
+ configRunningCapKey = config_map[NRUNNINGCAP]["key"]
271
+
272
+ tmp_log.debug(
273
+ msg_header + " got configuration configQueueLimit={} ({}), configQueueCap={} ({}),"
274
+ " configRunningCap={} ({})".format(configQueueLimit, configQueueLimitKey, configQueueCap, configQueueCapKey, configRunningCap, configRunningCapKey)
275
+ )
276
+
277
+ # get the jobs statistics for our wq/gs and expand the stats map
278
+ jobstats_map = self.__prepareJobStats(workQueue, resource_name, config_map)
279
+
280
+ tmp_log.debug(f"jobstats_map: {jobstats_map}")
281
+ nRunning_rt = jobstats_map["nRunning_rt"]
282
+ nRunning_gs = jobstats_map["nRunning_gs"]
283
+ nRunning_runningcap = jobstats_map["nRunning_runningcap"]
284
+ nNotRun_rt = jobstats_map["nNotRun_rt"]
285
+ nNotRun_gs = jobstats_map["nNotRun_gs"]
286
+ nNotRun_queuelimit = jobstats_map["nNotRun_queuelimit"]
287
+ nNotRun_queuecap = jobstats_map["nNotRun_queuecap"]
288
+ nDefine_rt = jobstats_map["nDefine_rt"]
289
+ nDefine_gs = jobstats_map["nDefine_gs"]
290
+ nDefine_queuelimit = jobstats_map["nDefine_queuelimit"]
291
+ nDefine_queuecap = jobstats_map["nDefine_queuecap"]
292
+ nWaiting_rt = jobstats_map["nWaiting_rt"]
293
+ nWaiting_gs = jobstats_map["nWaiting_gs"]
294
+
295
+ # check if higher prio tasks are waiting
296
+ if workQueue.queue_name in non_rt_wqs:
297
+ # find highest priority of currently defined jobs
298
+ tmpStat, highestPrioJobStat = self.taskBufferIF.getHighestPrioJobStat_JEDI(prodSourceLabel, cloud_name, workQueue)
299
+ # the highest priority of waiting tasks
300
+ highestPrioWaiting = self.taskBufferIF.checkWaitingTaskPrio_JEDI(vo, workQueue, prodSourceLabel, cloud_name)
301
+ else:
302
+ # find highest priority of currently defined jobs
303
+ tmpStat, highestPrioJobStat = self.taskBufferIF.getHighestPrioJobStat_JEDI(prodSourceLabel, cloud_name, workQueue, resource_name)
304
+ # the highest priority of waiting tasks
305
+ highestPrioWaiting = self.taskBufferIF.checkWaitingTaskPrio_JEDI(vo, workQueue, prodSourceLabel, cloud_name, resource_name)
306
+
307
+ highestPrioInPandaDB = highestPrioJobStat["highestPrio"]
308
+ nNotRunHighestPrio = highestPrioJobStat["nNotRun"]
309
+ if highestPrioWaiting is None:
310
+ msg_body = "failed to get the highest priority of waiting tasks"
311
+ tmp_log.error(f"{msg_header} {msg_body}")
312
+ return self.retTmpError
313
+
314
+ # high priority tasks are waiting
315
+ highPrioQueued = False
316
+ if prodSourceLabel != "user":
317
+ if highestPrioWaiting > highestPrioInPandaDB or (highestPrioWaiting == highestPrioInPandaDB and nNotRunHighestPrio < nJobsInBunchMin):
318
+ highPrioQueued = True
319
+ tmp_log.debug(
320
+ "{0} highestPrio waiting:{1} inPanda:{2} numNotRun:{3} -> highPrioQueued={4}".format(
321
+ msg_header, highestPrioWaiting, highestPrioInPandaDB, nNotRunHighestPrio, highPrioQueued
322
+ )
323
+ )
324
+ # set maximum number of jobs to be submitted
325
+ if workQueue.queue_name in non_rt_wqs:
326
+ tmpRemainingSlot = int(nRunning_gs * threshold - nNotRun_gs)
327
+ else:
328
+ tmpRemainingSlot = int(nRunning_rt * threshold - nNotRun_rt)
329
+ # use the lower limit to avoid creating too many _sub/_dis datasets
330
+ nJobsInBunch = min(max(nJobsInBunchMin, tmpRemainingSlot), nJobsInBunchMax)
331
+
332
+ if configQueueLimit is not None:
333
+ nQueueLimit = configQueueLimit
334
+ else:
335
+ nQueueLimit = nJobsInBunch * nBunch
336
+
337
+ # use nPrestage for reprocessing
338
+ if workQueue.queue_name in ["Heavy Ion", "Reprocessing default"]:
339
+ # reset nJobsInBunch
340
+ if nQueueLimit > (nNotRun_queuelimit + nDefine_queuelimit):
341
+ tmpRemainingSlot = nQueueLimit - (nNotRun_queuelimit + nDefine_queuelimit)
342
+ if tmpRemainingSlot > nJobsInBunch:
343
+ nJobsInBunch = min(tmpRemainingSlot, nJobsInBunchMax)
344
+
345
+ # get cap
346
+ # set number of jobs to be submitted
347
+ if configQueueCap is None:
348
+ self.setMaxNumJobs(nJobsInBunch // nParallel)
349
+ else:
350
+ self.setMaxNumJobs(configQueueCap // nParallelCap)
351
+
352
+ # get total walltime
353
+ totWalltime = self.taskBufferIF.getTotalWallTime_JEDI(vo, prodSourceLabel, workQueue, resource_name)
354
+
355
+ # log the current situation and limits
356
+ tmp_log.info(f"{msg_header} nQueueLimit={nQueueLimit} nRunCap={configRunningCap} nQueueCap={configQueueCap}")
357
+ tmp_log.info(f"{msg_header} at global share level: nQueued={nNotRun_gs + nDefine_gs} nDefine={nDefine_gs} nRunning={nRunning_gs}")
358
+ tmpMsg = ""
359
+ if config_map[NQUEUECAP]["level"] == LEVEL_MS:
360
+ tmpMsg = f"{msg_header} at MCORE/SCORE level: "
361
+ tmpMsg += f"nQueued_ms={nNotRun_queuecap} "
362
+ if config_map[NRUNNINGCAP]["level"] == LEVEL_MS:
363
+ if not tmpMsg:
364
+ tmpMsg = f"{msg_header} at MCORE/SCORE level: "
365
+ tmpMsg += f"nRunning_ms={nRunning_runningcap} "
366
+ if tmpMsg:
367
+ tmp_log.info(tmpMsg)
368
+ tmp_log.info(
369
+ "{0} at resource type level: nQueued_rt={1} nDefine_rt={2} nRunning_rt={3} totWalltime={4}".format(
370
+ msg_header, nNotRun_rt + nDefine_rt, nDefine_rt, nRunning_rt, totWalltime
371
+ )
372
+ )
373
+
374
+ # check number of jobs when high priority jobs are not waiting. test jobs are sent without throttling
375
+ limitPriority = False
376
+ if (
377
+ workQueue.queue_name not in non_rt_wqs
378
+ and nRunning_rt == 0
379
+ and (nNotRun_queuelimit + nDefine_queuelimit) > nQueueLimit
380
+ and (totWalltime is None or totWalltime > minTotalWalltime)
381
+ ):
382
+ limitPriority = True
383
+ if not highPrioQueued:
384
+ # pilot is not running or DDM has a problem
385
+ msg_body = "SKIP no running and enough nQueued_queuelimit={}>({}={}) & totWalltime({})>{} ".format(
386
+ nNotRun_queuelimit + nDefine_queuelimit, configQueueLimitKey, nQueueLimit, totWalltime, minTotalWalltime
387
+ )
388
+ tmp_log.info(f"{msg_header} {msg_body}")
389
+ tmp_log.sendMsg(f"{msg_header} {msg_body}", self.msgType, msgLevel="info", escapeChar=True)
390
+ return self.retMergeUnThr
391
+
392
+ elif workQueue.queue_name in non_rt_wqs and nRunning_gs == 0 and (nNotRun_queuelimit + nDefine_queuelimit) > nQueueLimit:
393
+ limitPriority = True
394
+ if not highPrioQueued:
395
+ # pilot is not running or DDM has a problem
396
+ msg_body = f"SKIP no running and enough nQueued_queuelimit={nNotRun_queuelimit + nDefine_queuelimit}>({configQueueLimitKey}={nQueueLimit})"
397
+ tmp_log.info(f"{msg_header} {msg_body}")
398
+ tmp_log.sendMsg(f"{msg_header} {msg_body}", self.msgType, msgLevel="info", escapeChar=True)
399
+ return self.retMergeUnThr
400
+
401
+ elif (
402
+ workQueue.queue_name not in non_rt_wqs
403
+ and nRunning_rt != 0
404
+ and float(nNotRun_rt + nDefine_rt) / float(nRunning_rt) > threshold
405
+ and (nNotRun_queuelimit + nDefine_queuelimit) > nQueueLimit
406
+ and (totWalltime is None or totWalltime > minTotalWalltime)
407
+ ):
408
+ limitPriority = True
409
+ if not highPrioQueued:
410
+ # enough jobs in Panda
411
+ msg_body = "SKIP nQueued_rt({})/nRunning_rt({})>{} & nQueued_queuelimit={}>({}={}) & totWalltime({})>{}".format(
412
+ nNotRun_rt + nDefine_rt,
413
+ nRunning_rt,
414
+ threshold,
415
+ nNotRun_queuelimit + nDefine_queuelimit,
416
+ configQueueLimitKey,
417
+ nQueueLimit,
418
+ totWalltime,
419
+ minTotalWalltime,
420
+ )
421
+ tmp_log.info(f"{msg_header} {msg_body}")
422
+ tmp_log.sendMsg(f"{msg_header} {msg_body}", self.msgType, msgLevel="info", escapeChar=True)
423
+ return self.retMergeUnThr
424
+
425
+ elif (
426
+ workQueue.queue_name in non_rt_wqs
427
+ and nRunning_gs != 0
428
+ and float(nNotRun_gs + nDefine_gs) / float(nRunning_gs) > threshold
429
+ and (nNotRun_queuelimit + nDefine_queuelimit) > nQueueLimit
430
+ ):
431
+ limitPriority = True
432
+ if not highPrioQueued:
433
+ # enough jobs in Panda
434
+ msg_body = "SKIP nQueued_gs({})/nRunning_gs({})>{} & nQueued_queuelimit={}>({}={})".format(
435
+ nNotRun_gs + nDefine_gs, nRunning_gs, threshold, nNotRun_queuelimit + nDefine_queuelimit, configQueueLimitKey, nQueueLimit
436
+ )
437
+ tmp_log.info(f"{msg_header} {msg_body}")
438
+ tmp_log.sendMsg(f"{msg_header} {msg_body}", self.msgType, msgLevel="info", escapeChar=True)
439
+ return self.retMergeUnThr
440
+
441
+ elif nDefine_queuelimit > nQueueLimit:
442
+ limitPriority = True
443
+ if not highPrioQueued:
444
+ # brokerage is stuck
445
+ msg_body = f"SKIP too many nDefined_queuelimit={nDefine_queuelimit}>({configQueueLimitKey}={nQueueLimit})"
446
+ tmp_log.info(f"{msg_header} {msg_body}")
447
+ tmp_log.sendMsg(f"{msg_header} {msg_body}", self.msgType, msgLevel="info", escapeChar=True)
448
+ return self.retMergeUnThr
449
+
450
+ elif nWaiting_rt > max(nRunning_rt * nWaitingLimit, nJobsInBunch * nWaitingBunchLimit):
451
+ limitPriority = True
452
+ if not highPrioQueued:
453
+ # too many waiting
454
+ msg_body = f"SKIP too many nWaiting_rt({nWaiting_rt})>max(nRunning_rt({nRunning_rt})x{nWaitingLimit},{nJobsInBunch}x{nWaitingBunchLimit})"
455
+ tmp_log.info(f"{msg_header} {msg_body}")
456
+ tmp_log.sendMsg(f"{msg_header} {msg_body}", self.msgType, msgLevel="info", escapeChar=True)
457
+ return self.retMergeUnThr
458
+
459
+ elif configRunningCap and nRunning_runningcap > configRunningCap:
460
+ # cap on running
461
+ msg_body = f"SKIP nRunning_runningcap({nRunning_runningcap})>nRunningCap({configRunningCapKey}={configRunningCap})"
462
+ tmp_log.info(f"{msg_header} {msg_body}")
463
+ tmp_log.sendMsg(f"{msg_header} {msg_body}", self.msgType, msgLevel="info", escapeChar=True)
464
+ return self.retMergeUnThr
465
+
466
+ elif configQueueCap and nNotRun_queuecap + nDefine_queuecap > configQueueCap:
467
+ limitPriority = True
468
+ if not highPrioQueued:
469
+ # cap on queued
470
+ msg_body = f"SKIP nQueued_queuecap({nNotRun_queuecap + nDefine_queuecap})>nQueueCap({configQueueCapKey}={configQueueCap})"
471
+ tmp_log.info(f"{msg_header} {msg_body}")
472
+ tmp_log.sendMsg(f"{msg_header} {msg_body}", self.msgType, msgLevel="info", escapeChar=True)
473
+ return self.retMergeUnThr
474
+
475
+ # get jobs from prodDB
476
+ limitPriorityValue = None
477
+ if limitPriority:
478
+ limitPriorityValue = highestPrioWaiting
479
+ self.setMinPriority(limitPriorityValue)
480
+ else:
481
+ # not enough jobs are queued
482
+ if (
483
+ (nNotRun_queuelimit + nDefine_queuelimit < nQueueLimit * 0.9)
484
+ or (workQueue.queue_name in non_rt_wqs and nNotRun_gs + nDefine_gs < nRunning_gs)
485
+ or (workQueue.queue_name not in non_rt_wqs and nNotRun_rt + nDefine_rt < nRunning_rt)
486
+ ):
487
+ tmp_log.debug(msg_header + " not enough jobs queued")
488
+ self.notEnoughJobsQueued()
489
+ self.setMaxNumJobs(max(self.maxNumJobs, nQueueLimit / 20))
490
+
491
+ msg_body = f"PASS - not throttled since priority limit={limitPriorityValue} maxNumJobs={self.maxNumJobs}"
492
+ tmp_log.info(msg_header + " " + msg_body)
493
+ return self.retUnThrottled
494
+
495
+
496
+ Interaction.installSC(JobThrottlerBase)
File without changes
File without changes
File without changes
File without changes