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.
- panda_server_source-0.8.0.dist-info/METADATA +55 -0
- panda_server_source-0.8.0.dist-info/RECORD +375 -0
- panda_server_source-0.8.0.dist-info/WHEEL +4 -0
- panda_server_source-0.8.0.dist-info/licenses/LICENSE.txt +202 -0
- pandajedi/__init__.py +0 -0
- pandajedi/jedibrokerage/AtlasAnalJobBroker.py +2343 -0
- pandajedi/jedibrokerage/AtlasBrokerUtils.py +1292 -0
- pandajedi/jedibrokerage/AtlasProdJobBroker.py +2064 -0
- pandajedi/jedibrokerage/AtlasProdTaskBroker.py +629 -0
- pandajedi/jedibrokerage/GenJobBroker.py +381 -0
- pandajedi/jedibrokerage/JobBrokerBase.py +133 -0
- pandajedi/jedibrokerage/TaskBrokerBase.py +15 -0
- pandajedi/jedibrokerage/__init__.py +0 -0
- pandajedi/jediconfig/__init__.py +0 -0
- pandajedi/jediconfig/jedi_config.py +40 -0
- pandajedi/jedicore/FactoryBase.py +182 -0
- pandajedi/jedicore/Interaction.py +433 -0
- pandajedi/jedicore/JediDBProxy.py +56 -0
- pandajedi/jedicore/JediDBProxyPool.py +37 -0
- pandajedi/jedicore/JediDBSchemaInfo.py +17 -0
- pandajedi/jedicore/JediException.py +13 -0
- pandajedi/jedicore/JediTaskBuffer.py +984 -0
- pandajedi/jedicore/JediTaskBufferInterface.py +50 -0
- pandajedi/jedicore/MsgWrapper.py +124 -0
- pandajedi/jedicore/ProcessUtils.py +34 -0
- pandajedi/jedicore/SiteCandidate.py +90 -0
- pandajedi/jedicore/ThreadUtils.py +205 -0
- pandajedi/jedicore/__init__.py +0 -0
- pandajedi/jediddm/AtlasDDMClient.py +1708 -0
- pandajedi/jediddm/DDMClientBase.py +16 -0
- pandajedi/jediddm/DDMInterface.py +83 -0
- pandajedi/jediddm/GenDDMClient.py +17 -0
- pandajedi/jediddm/__init__.py +0 -0
- pandajedi/jedidog/AtlasAnalWatchDog.py +648 -0
- pandajedi/jedidog/AtlasDataCarouselWatchDog.py +189 -0
- pandajedi/jedidog/AtlasDataLocalityUpdaterWatchDog.py +215 -0
- pandajedi/jedidog/AtlasProdWatchDog.py +443 -0
- pandajedi/jedidog/AtlasQueueFillerWatchDog.py +800 -0
- pandajedi/jedidog/AtlasTaskWithholderWatchDog.py +245 -0
- pandajedi/jedidog/AtlasWorkflowManagerWatchDog.py +63 -0
- pandajedi/jedidog/GenWatchDog.py +21 -0
- pandajedi/jedidog/JumboWatchDog.py +147 -0
- pandajedi/jedidog/TypicalWatchDogBase.py +122 -0
- pandajedi/jedidog/WatchDogBase.py +53 -0
- pandajedi/jedidog/__init__.py +0 -0
- pandajedi/jediexec/reniceJEDI.py +25 -0
- pandajedi/jedigen/AtlasTaskGenerator.py +110 -0
- pandajedi/jedigen/TaskGeneratorBase.py +15 -0
- pandajedi/jedigen/__init__.py +0 -0
- pandajedi/jedimsgprocessor/__init__.py +0 -0
- pandajedi/jedimsgprocessor/ai_parameter_adjuster_msg_processor +71 -0
- pandajedi/jedimsgprocessor/atlas_idds_msg_processor.py +66 -0
- pandajedi/jedimsgprocessor/base_msg_processor.py +33 -0
- pandajedi/jedimsgprocessor/forwarding_msg_processor.py +29 -0
- pandajedi/jedimsgprocessor/hpo_msg_processor.py +93 -0
- pandajedi/jedimsgprocessor/jedi_contents_feeder_msg_processor.py +63 -0
- pandajedi/jedimsgprocessor/jedi_job_generator_msg_processor.py +185 -0
- pandajedi/jedimsgprocessor/jedi_post_processor_msg_processor.py +82 -0
- pandajedi/jedimsgprocessor/kafka_msg_processor.py +44 -0
- pandajedi/jedimsgprocessor/panda_callback_msg_processor.py +182 -0
- pandajedi/jedimsgprocessor/panda_to_jedi_msg_processor.py +74 -0
- pandajedi/jedimsgprocessor/processing_msg_processor.py +134 -0
- pandajedi/jedimsgprocessor/status_report_msg_processor.py +129 -0
- pandajedi/jedimsgprocessor/tape_carousel_msg_processor.py +118 -0
- pandajedi/jedimsgprocessor/workflow_manager_msg_processor.py +89 -0
- pandajedi/jediorder/ContentsFeeder.py +785 -0
- pandajedi/jediorder/JediDaemon.py +27 -0
- pandajedi/jediorder/JediKnight.py +55 -0
- pandajedi/jediorder/JediMaster.py +238 -0
- pandajedi/jediorder/JediMsgProcessor.py +32 -0
- pandajedi/jediorder/JobBroker.py +33 -0
- pandajedi/jediorder/JobGenerator.py +2763 -0
- pandajedi/jediorder/JobSplitter.py +308 -0
- pandajedi/jediorder/JobThrottler.py +28 -0
- pandajedi/jediorder/PostProcessor.py +166 -0
- pandajedi/jediorder/TaskBroker.py +268 -0
- pandajedi/jediorder/TaskCommando.py +334 -0
- pandajedi/jediorder/TaskGenerator.py +17 -0
- pandajedi/jediorder/TaskRefiner.py +611 -0
- pandajedi/jediorder/TaskSetupper.py +17 -0
- pandajedi/jediorder/WatchDog.py +79 -0
- pandajedi/jediorder/__init__.py +0 -0
- pandajedi/jedipprocess/AtlasAnalPostProcessor.py +404 -0
- pandajedi/jedipprocess/AtlasPostProcessorUtils.py +50 -0
- pandajedi/jedipprocess/AtlasProdPostProcessor.py +178 -0
- pandajedi/jedipprocess/GenPostProcessor.py +35 -0
- pandajedi/jedipprocess/MailTemplates.py +185 -0
- pandajedi/jedipprocess/PostProcessorBase.py +269 -0
- pandajedi/jedipprocess/__init__.py +0 -0
- pandajedi/jedirefine/AtlasAnalTaskRefiner.py +259 -0
- pandajedi/jedirefine/AtlasProdTaskRefiner.py +162 -0
- pandajedi/jedirefine/GenTaskRefiner.py +61 -0
- pandajedi/jedirefine/RefinerUtils.py +154 -0
- pandajedi/jedirefine/TaskRefinerBase.py +996 -0
- pandajedi/jedirefine/__init__.py +0 -0
- pandajedi/jedisetup/AtlasTaskSetupper.py +309 -0
- pandajedi/jedisetup/GenTaskSetupper.py +16 -0
- pandajedi/jedisetup/SimpleTaskSetupper.py +152 -0
- pandajedi/jedisetup/TaskSetupperBase.py +15 -0
- pandajedi/jedisetup/__init__.py +0 -0
- pandajedi/jeditest/SchemaChecker.py +41 -0
- pandajedi/jeditest/addContWoSoTask.py +54 -0
- pandajedi/jeditest/addDataCarouselRequest.py +47 -0
- pandajedi/jeditest/addEventServiceTask.py +101 -0
- pandajedi/jeditest/addHpoTask.py +81 -0
- pandajedi/jeditest/addIDDSStageInRequest.py +56 -0
- pandajedi/jeditest/addNonAtlasTask.py +71 -0
- pandajedi/jeditest/addNonAtlasTaskEnc.py +64 -0
- pandajedi/jeditest/addTestTask.py +124 -0
- pandajedi/jeditest/addTestTaskParamToDEFT.py +70 -0
- pandajedi/jeditest/addTestTaskWithMerger.py +97 -0
- pandajedi/jeditest/brokerTest.py +78 -0
- pandajedi/jeditest/cancelDataCarouselRequest.py +35 -0
- pandajedi/jeditest/contentsFeederTest.py +28 -0
- pandajedi/jeditest/contentsFeederTestWithTask.py +18 -0
- pandajedi/jeditest/ddmTest.py +4 -0
- pandajedi/jeditest/jobGenForOneTask.py +38 -0
- pandajedi/jeditest/jobGeneratorTest.py +43 -0
- pandajedi/jeditest/jobSplitterTest.py +104 -0
- pandajedi/jeditest/jobThrottlerTest.py +22 -0
- pandajedi/jeditest/msgProcessorTest.py +9 -0
- pandajedi/jeditest/postProcessorTest.py +18 -0
- pandajedi/jeditest/resubmitDataCarouselRequest.py +35 -0
- pandajedi/jeditest/resubmitTaskParam.py +20 -0
- pandajedi/jeditest/taskBrokerTest.py +22 -0
- pandajedi/jeditest/taskBrokerTestWithTask.py +38 -0
- pandajedi/jeditest/taskBufferTest.py +5 -0
- pandajedi/jeditest/taskCommandoTest.py +28 -0
- pandajedi/jeditest/taskRefinerTest.py +30 -0
- pandajedi/jeditest/testOneTaskToRefine.py +49 -0
- pandajedi/jeditest/testOneTaskToTaskBroker.py +42 -0
- pandajedi/jeditest/testPandaDDMMap.py +62 -0
- pandajedi/jeditest/updateDataCarouselRequestParams.py +50 -0
- pandajedi/jeditest/watchDogTest.py +25 -0
- pandajedi/jeditest/workQueueTest.py +22 -0
- pandajedi/jedithrottle/AtlasAnalJobThrottler.py +19 -0
- pandajedi/jedithrottle/AtlasProdJobThrottler.py +18 -0
- pandajedi/jedithrottle/GenJobThrottler.py +26 -0
- pandajedi/jedithrottle/JobThrottlerBase.py +496 -0
- pandajedi/jedithrottle/__init__.py +0 -0
- pandaserver/__init__.py +0 -0
- pandaserver/api/__init__.py +0 -0
- pandaserver/api/v1/__init__.py +0 -0
- pandaserver/api/v1/common.py +339 -0
- pandaserver/api/v1/credential_management_api.py +372 -0
- pandaserver/api/v1/data_carousel_api.py +264 -0
- pandaserver/api/v1/event_api.py +269 -0
- pandaserver/api/v1/file_server_api.py +942 -0
- pandaserver/api/v1/harvester_api.py +445 -0
- pandaserver/api/v1/http_client.py +166 -0
- pandaserver/api/v1/idds_api.py +180 -0
- pandaserver/api/v1/job_api.py +463 -0
- pandaserver/api/v1/metaconfig_api.py +122 -0
- pandaserver/api/v1/pilot_api.py +895 -0
- pandaserver/api/v1/statistics_api.py +207 -0
- pandaserver/api/v1/system_api.py +186 -0
- pandaserver/api/v1/task_api.py +1520 -0
- pandaserver/api/v1/tests/__init__.py +0 -0
- pandaserver/api/v1/tests/credential_management_api_tests.py +116 -0
- pandaserver/api/v1/tests/data_carousel_api_tests.py +82 -0
- pandaserver/api/v1/tests/harvester_api_tests.py +188 -0
- pandaserver/api/v1/tests/idds_api_tests.py +45 -0
- pandaserver/api/v1/tests/job_api_tests.py +112 -0
- pandaserver/api/v1/tests/pilot_api_tests.py +154 -0
- pandaserver/api/v1/tests/statistics_api_tests.py +104 -0
- pandaserver/api/v1/tests/system_api_tests.py +58 -0
- pandaserver/api/v1/tests/task_api_tests.py +590 -0
- pandaserver/api/v1/version.py +2 -0
- pandaserver/api/v1/workflow_api.py +136 -0
- pandaserver/brokerage/SiteMapper.py +406 -0
- pandaserver/brokerage/__init__.py +0 -0
- pandaserver/brokerage/broker.py +272 -0
- pandaserver/config/__init__.py +0 -0
- pandaserver/config/config_utils.py +15 -0
- pandaserver/config/daemon_config.py +29 -0
- pandaserver/config/mcp_config.py +38 -0
- pandaserver/config/panda_config.py +233 -0
- pandaserver/configurator/Carbon.py +65 -0
- pandaserver/configurator/Configurator.py +908 -0
- pandaserver/configurator/__init__.py +0 -0
- pandaserver/configurator/aux.py +73 -0
- pandaserver/daemons/__init__.py +0 -0
- pandaserver/daemons/master.py +110 -0
- pandaserver/daemons/master_systemd.py +79 -0
- pandaserver/daemons/scripts/__init__.py +0 -0
- pandaserver/daemons/scripts/add_main.py +264 -0
- pandaserver/daemons/scripts/add_sub.py +221 -0
- pandaserver/daemons/scripts/cache_pilots.py +47 -0
- pandaserver/daemons/scripts/cache_schedconfig.py +286 -0
- pandaserver/daemons/scripts/carbon.py +50 -0
- pandaserver/daemons/scripts/configurator.py +94 -0
- pandaserver/daemons/scripts/copyArchive.py +1387 -0
- pandaserver/daemons/scripts/datasetManager.py +1154 -0
- pandaserver/daemons/scripts/dummy_test.py +25 -0
- pandaserver/daemons/scripts/evpPD2P.py +144 -0
- pandaserver/daemons/scripts/hs_scrapers.py +264 -0
- pandaserver/daemons/scripts/metric_collector.py +927 -0
- pandaserver/daemons/scripts/panda_activeusers_query.py +80 -0
- pandaserver/daemons/scripts/pilotStreaming.py +109 -0
- pandaserver/daemons/scripts/process_workflow_files_daemon.py +166 -0
- pandaserver/daemons/scripts/recover_lost_files_daemon.py +177 -0
- pandaserver/daemons/scripts/task_evaluator.py +405 -0
- pandaserver/daemons/scripts/tmpwatch.py +70 -0
- pandaserver/daemons/scripts/worker_synchronization.py +97 -0
- pandaserver/daemons/utils.py +753 -0
- pandaserver/dataservice/DataServiceUtils.py +323 -0
- pandaserver/dataservice/ErrorCode.py +25 -0
- pandaserver/dataservice/RecoverLostFilesCore.py +322 -0
- pandaserver/dataservice/__init__.py +0 -0
- pandaserver/dataservice/activator.py +79 -0
- pandaserver/dataservice/adder_atlas_plugin.py +1106 -0
- pandaserver/dataservice/adder_dummy_plugin.py +31 -0
- pandaserver/dataservice/adder_gen.py +954 -0
- pandaserver/dataservice/adder_plugin_base.py +27 -0
- pandaserver/dataservice/adder_result.py +75 -0
- pandaserver/dataservice/adder_simple_plugin.py +160 -0
- pandaserver/dataservice/closer.py +247 -0
- pandaserver/dataservice/closer_atlas_plugin.py +90 -0
- pandaserver/dataservice/ddm.py +1381 -0
- pandaserver/dataservice/ddm_handler.py +95 -0
- pandaserver/dataservice/dyn_data_distributer.py +824 -0
- pandaserver/dataservice/event_lookup_client_ei.py +77 -0
- pandaserver/dataservice/event_picker.py +268 -0
- pandaserver/dataservice/finisher.py +194 -0
- pandaserver/dataservice/setupper.py +225 -0
- pandaserver/dataservice/setupper_atlas_plugin.py +1851 -0
- pandaserver/dataservice/setupper_dummy_plugin.py +47 -0
- pandaserver/dataservice/setupper_plugin_base.py +67 -0
- pandaserver/jobdispatcher/DispatcherUtils.py +35 -0
- pandaserver/jobdispatcher/ErrorCode.py +19 -0
- pandaserver/jobdispatcher/JobDispatcher.py +1625 -0
- pandaserver/jobdispatcher/Protocol.py +443 -0
- pandaserver/jobdispatcher/Watcher.py +186 -0
- pandaserver/jobdispatcher/__init__.py +0 -0
- pandaserver/pandamcp/__init__.py +0 -0
- pandaserver/pandamcp/mcp_main.py +56 -0
- pandaserver/pandamcp/mcp_test_client.py +95 -0
- pandaserver/pandamcp/mcp_utils.py +74 -0
- pandaserver/proxycache/__init__.py +0 -0
- pandaserver/proxycache/panda_proxy_cache.py +240 -0
- pandaserver/proxycache/token_cache.py +141 -0
- pandaserver/server/.gacl +6 -0
- pandaserver/server/panda.py +539 -0
- pandaserver/srvcore/CoreUtils.py +572 -0
- pandaserver/srvcore/MailUtils.py +106 -0
- pandaserver/srvcore/__init__.py +0 -0
- pandaserver/srvcore/allowed_methods.py +100 -0
- pandaserver/srvcore/oidc_utils.py +152 -0
- pandaserver/srvcore/panda_request.py +196 -0
- pandaserver/srvcore/srv_msg_utils.py +42 -0
- pandaserver/taskbuffer/ConBridge.py +513 -0
- pandaserver/taskbuffer/DBProxyPool.py +95 -0
- pandaserver/taskbuffer/DataCarousel.py +3053 -0
- pandaserver/taskbuffer/DatasetSpec.py +137 -0
- pandaserver/taskbuffer/DdmSpec.py +201 -0
- pandaserver/taskbuffer/ErrorCode.py +87 -0
- pandaserver/taskbuffer/EventServiceUtils.py +396 -0
- pandaserver/taskbuffer/FileSpec.py +290 -0
- pandaserver/taskbuffer/GlobalShares.py +244 -0
- pandaserver/taskbuffer/HarvesterMetricsSpec.py +92 -0
- pandaserver/taskbuffer/Initializer.py +82 -0
- pandaserver/taskbuffer/InputChunk.py +1080 -0
- pandaserver/taskbuffer/JediCacheSpec.py +57 -0
- pandaserver/taskbuffer/JediDatasetSpec.py +588 -0
- pandaserver/taskbuffer/JediFileSpec.py +242 -0
- pandaserver/taskbuffer/JediTaskSpec.py +1687 -0
- pandaserver/taskbuffer/JobSpec.py +1006 -0
- pandaserver/taskbuffer/JobUtils.py +232 -0
- pandaserver/taskbuffer/NucleusSpec.py +116 -0
- pandaserver/taskbuffer/OraDBProxy.py +174 -0
- pandaserver/taskbuffer/PanDAMsgProcessor.py +8 -0
- pandaserver/taskbuffer/PandaDBSchemaInfo.py +18 -0
- pandaserver/taskbuffer/ParseJobXML.py +350 -0
- pandaserver/taskbuffer/PickleFileSpec.py +18 -0
- pandaserver/taskbuffer/PickleJobSpec.py +25 -0
- pandaserver/taskbuffer/PrioUtil.py +40 -0
- pandaserver/taskbuffer/ProcessGroups.py +111 -0
- pandaserver/taskbuffer/ResourceSpec.py +175 -0
- pandaserver/taskbuffer/SQLDumper.py +37 -0
- pandaserver/taskbuffer/SQLManager.py +60 -0
- pandaserver/taskbuffer/SiteSpec.py +304 -0
- pandaserver/taskbuffer/SupErrors.py +10 -0
- pandaserver/taskbuffer/TaskBuffer.py +2882 -0
- pandaserver/taskbuffer/TaskBufferInterface.py +163 -0
- pandaserver/taskbuffer/Utils.py +848 -0
- pandaserver/taskbuffer/WorkQueue.py +227 -0
- pandaserver/taskbuffer/WorkQueueMapper.py +203 -0
- pandaserver/taskbuffer/WorkerSpec.py +143 -0
- pandaserver/taskbuffer/WrappedCursor.py +487 -0
- pandaserver/taskbuffer/WrappedPickle.py +88 -0
- pandaserver/taskbuffer/WrappedPostgresConn.py +24 -0
- pandaserver/taskbuffer/__init__.py +0 -0
- pandaserver/taskbuffer/db_proxy_mods/OraDBProxy_structure.png +0 -0
- pandaserver/taskbuffer/db_proxy_mods/__init__.py +7 -0
- pandaserver/taskbuffer/db_proxy_mods/base_module.py +841 -0
- pandaserver/taskbuffer/db_proxy_mods/data_carousel_module.py +772 -0
- pandaserver/taskbuffer/db_proxy_mods/entity_module.py +3804 -0
- pandaserver/taskbuffer/db_proxy_mods/job_complex_module.py +5661 -0
- pandaserver/taskbuffer/db_proxy_mods/job_standalone_module.py +2640 -0
- pandaserver/taskbuffer/db_proxy_mods/metrics_module.py +874 -0
- pandaserver/taskbuffer/db_proxy_mods/misc_standalone_module.py +4272 -0
- pandaserver/taskbuffer/db_proxy_mods/task_complex_module.py +6172 -0
- pandaserver/taskbuffer/db_proxy_mods/task_event_module.py +4953 -0
- pandaserver/taskbuffer/db_proxy_mods/task_standalone_module.py +4999 -0
- pandaserver/taskbuffer/db_proxy_mods/task_utils_module.py +2063 -0
- pandaserver/taskbuffer/db_proxy_mods/worker_module.py +1944 -0
- pandaserver/taskbuffer/db_proxy_mods/workflow_module.py +832 -0
- pandaserver/taskbuffer/retryModule.py +552 -0
- pandaserver/taskbuffer/task_split_rules.py +308 -0
- pandaserver/taskbuffer/workflow_processor.py +249 -0
- pandaserver/taskbuffer/wrapped_oracle_conn.py +18 -0
- pandaserver/test/SchemaChecker.py +40 -0
- pandaserver/test/__init__.py +0 -0
- pandaserver/test/banUser.py +43 -0
- pandaserver/test/boostPrio.py +19 -0
- pandaserver/test/boostUser.py +35 -0
- pandaserver/test/callbackDDM.py +11 -0
- pandaserver/test/daod_on_demand.py +95 -0
- pandaserver/test/finishJob.py +184 -0
- pandaserver/test/finishTaskJEDI.py +11 -0
- pandaserver/test/getJobs.py +53 -0
- pandaserver/test/killJob.py +79 -0
- pandaserver/test/killJobLowPrio.py +99 -0
- pandaserver/test/killJobsInTask.py +56 -0
- pandaserver/test/killTask.py +80 -0
- pandaserver/test/killTaskJEDI.py +11 -0
- pandaserver/test/killUser.py +83 -0
- pandaserver/test/lsst/README.txt +7 -0
- pandaserver/test/lsst/lsstSubmit.py +139 -0
- pandaserver/test/lsst/lsstSubmitMERGEtest.py +141 -0
- pandaserver/test/lsst/lsstSubmitPhosim332.py +53 -0
- pandaserver/test/lsst/prepare-client-tarball-from-bigpanda-server.sh +41 -0
- pandaserver/test/reassignJobs.py +17 -0
- pandaserver/test/reassignSite.py +82 -0
- pandaserver/test/reassignTask.py +117 -0
- pandaserver/test/reassignWaiting.py +39 -0
- pandaserver/test/recoverLostFiles.py +7 -0
- pandaserver/test/reloadInputDS.py +51 -0
- pandaserver/test/sendCommandToJob.py +26 -0
- pandaserver/test/setDebugMode.py +38 -0
- pandaserver/test/setPriority.py +28 -0
- pandaserver/test/testEvgen.py +60 -0
- pandaserver/test/testEvgen17.py +58 -0
- pandaserver/test/testG4sim.py +81 -0
- pandaserver/test/testG4sim17.py +90 -0
- pandaserver/test/testGlobalShares.py +131 -0
- pandaserver/test/testReco.py +103 -0
- pandaserver/test/testSimulReco14.py +98 -0
- pandaserver/test/testSiteMap.py +26 -0
- pandaserver/test/testUpdateWorkerPilotStatus.py +9 -0
- pandaserver/userinterface/Client.py +1686 -0
- pandaserver/userinterface/UserIF.py +1799 -0
- pandaserver/userinterface/__init__.py +0 -0
- pandaserver/workflow/__init__.py +0 -0
- pandaserver/workflow/data_handler_plugins/base_data_handler.py +48 -0
- pandaserver/workflow/data_handler_plugins/ddm_collection_data_handler.py +100 -0
- pandaserver/workflow/data_handler_plugins/panda_task_data_handler.py +140 -0
- pandaserver/workflow/pcwl_test.py +122 -0
- pandaserver/workflow/pcwl_utils.py +384 -0
- pandaserver/workflow/psnakemake_container.json +68 -0
- pandaserver/workflow/psnakemake_task.json +62 -0
- pandaserver/workflow/psnakemake_test.py +60 -0
- pandaserver/workflow/snakeparser/__init__.py +3 -0
- pandaserver/workflow/snakeparser/extensions.py +74 -0
- pandaserver/workflow/snakeparser/log.py +53 -0
- pandaserver/workflow/snakeparser/names.py +3 -0
- pandaserver/workflow/snakeparser/parser.py +332 -0
- pandaserver/workflow/snakeparser/utils.py +29 -0
- pandaserver/workflow/step_handler_plugins/base_step_handler.py +85 -0
- pandaserver/workflow/step_handler_plugins/panda_task_step_handler.py +280 -0
- pandaserver/workflow/workflow_base.py +531 -0
- pandaserver/workflow/workflow_core.py +1974 -0
- pandaserver/workflow/workflow_core_smoketest.py +388 -0
- pandaserver/workflow/workflow_parser.py +222 -0
- 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
|
pandaserver/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
File without changes
|