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,1387 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import math
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
import sys
|
|
6
|
+
import time
|
|
7
|
+
import traceback
|
|
8
|
+
|
|
9
|
+
import requests
|
|
10
|
+
from pandacommon.pandalogger.LogWrapper import LogWrapper
|
|
11
|
+
from pandacommon.pandalogger.PandaLogger import PandaLogger
|
|
12
|
+
from pandacommon.pandautils.PandaUtils import get_sql_IN_bind_variables, naive_utcnow
|
|
13
|
+
from pandacommon.pandautils.thread_utils import GenericThread
|
|
14
|
+
from urllib3.exceptions import InsecureRequestWarning
|
|
15
|
+
|
|
16
|
+
import pandaserver.userinterface.Client as Client
|
|
17
|
+
from pandaserver.brokerage.SiteMapper import SiteMapper
|
|
18
|
+
from pandaserver.config import panda_config
|
|
19
|
+
from pandaserver.jobdispatcher.Watcher import Watcher
|
|
20
|
+
from pandaserver.taskbuffer import EventServiceUtils
|
|
21
|
+
|
|
22
|
+
# logger
|
|
23
|
+
_logger = PandaLogger().getLogger("copyArchive")
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# main
|
|
27
|
+
def main(argv=tuple(), tbuf=None, **kwargs):
|
|
28
|
+
requester_id = GenericThread().get_full_id(__name__, sys.modules[__name__].__file__)
|
|
29
|
+
|
|
30
|
+
# password
|
|
31
|
+
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
|
|
32
|
+
|
|
33
|
+
_logger.debug("===================== start =====================")
|
|
34
|
+
|
|
35
|
+
# memory checker
|
|
36
|
+
def _memoryCheck(str):
|
|
37
|
+
try:
|
|
38
|
+
proc_status = "/proc/%d/status" % os.getpid()
|
|
39
|
+
procfile = open(proc_status)
|
|
40
|
+
name = ""
|
|
41
|
+
vmSize = ""
|
|
42
|
+
vmRSS = ""
|
|
43
|
+
# extract Name,VmSize,VmRSS
|
|
44
|
+
for line in procfile:
|
|
45
|
+
if line.startswith("Name:"):
|
|
46
|
+
name = line.split()[-1]
|
|
47
|
+
continue
|
|
48
|
+
if line.startswith("VmSize:"):
|
|
49
|
+
vmSize = ""
|
|
50
|
+
for item in line.split()[1:]:
|
|
51
|
+
vmSize += item
|
|
52
|
+
continue
|
|
53
|
+
if line.startswith("VmRSS:"):
|
|
54
|
+
vmRSS = ""
|
|
55
|
+
for item in line.split()[1:]:
|
|
56
|
+
vmRSS += item
|
|
57
|
+
continue
|
|
58
|
+
procfile.close()
|
|
59
|
+
_logger.debug(f"MemCheck - {os.getpid()} Name={name} VSZ={vmSize} RSS={vmRSS} : {str}")
|
|
60
|
+
except Exception:
|
|
61
|
+
type, value, traceBack = sys.exc_info()
|
|
62
|
+
_logger.error(f"memoryCheck() : {type} {value}")
|
|
63
|
+
_logger.debug(f"MemCheck - {os.getpid()} unknown : {str}")
|
|
64
|
+
return
|
|
65
|
+
|
|
66
|
+
_memoryCheck("start")
|
|
67
|
+
|
|
68
|
+
# instantiate TB
|
|
69
|
+
from pandaserver.taskbuffer.TaskBuffer import taskBuffer
|
|
70
|
+
|
|
71
|
+
taskBuffer.init(
|
|
72
|
+
panda_config.dbhost,
|
|
73
|
+
panda_config.dbpasswd,
|
|
74
|
+
nDBConnection=1,
|
|
75
|
+
useTimeout=True,
|
|
76
|
+
requester=requester_id,
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# instantiate sitemapper
|
|
80
|
+
siteMapper = SiteMapper(taskBuffer)
|
|
81
|
+
|
|
82
|
+
# kick merging jobs
|
|
83
|
+
_logger.debug("Kick merging session")
|
|
84
|
+
try:
|
|
85
|
+
# get min PandaID for failed jobs in Active table
|
|
86
|
+
sql = (
|
|
87
|
+
"SELECT j.PandaID, j.jediTaskID, f.destinationDBlock "
|
|
88
|
+
f"FROM {panda_config.schemaPANDA}.jobsActive4 j, {panda_config.schemaPANDA}.filesTable4 f "
|
|
89
|
+
"WHERE f.PandaID=j.PandaID AND j.prodSourceLabel=:prodSourceLabel AND j.jobStatus=:jobStatus "
|
|
90
|
+
"AND f.type=:type "
|
|
91
|
+
)
|
|
92
|
+
var_map = {":jobStatus": "merging", ":prodSourceLabel": "user", ":type": "log"}
|
|
93
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
94
|
+
destination_blocks = {}
|
|
95
|
+
if res is not None:
|
|
96
|
+
# collect destination blocks
|
|
97
|
+
for panda_id, task_id, destination_block in res:
|
|
98
|
+
if destination_block in destination_blocks:
|
|
99
|
+
continue
|
|
100
|
+
destination_blocks[destination_block] = (panda_id, task_id)
|
|
101
|
+
# loop over all destination blocks
|
|
102
|
+
for destination_block, (panda_id, task_id) in destination_blocks.items():
|
|
103
|
+
# check
|
|
104
|
+
tmp_log = LogWrapper(_logger, f"kick_merge < jediTaskID={task_id} dest={destination_block} >")
|
|
105
|
+
tmp_log.debug("check")
|
|
106
|
+
sqlC = f"WITH w AS (SELECT PandaID FROM {panda_config.schemaPANDA}.filesTable4 WHERE destinationDBlock=:destinationDBlock) "
|
|
107
|
+
sqlC += "SELECT COUNT(*) FROM ("
|
|
108
|
+
sqlC += "SELECT j.PandaID FROM ATLAS_PANDA.jobsActive4 j, w "
|
|
109
|
+
sqlC += "WHERE j.PandaID=w.PandaID "
|
|
110
|
+
sqlC += "AND NOT j.jobStatus IN (:jobStatus1,:jobStatus2) "
|
|
111
|
+
sqlC += "UNION "
|
|
112
|
+
sqlC += "SELECT j.PandaID FROM ATLAS_PANDA.jobsDefined4 j, w "
|
|
113
|
+
sqlC += "WHERE j.PandaID=w.PandaID "
|
|
114
|
+
sqlC += "AND NOT j.jobStatus IN (:jobStatus1,:jobStatus2) "
|
|
115
|
+
sqlC += ") "
|
|
116
|
+
var_map = {}
|
|
117
|
+
var_map[":jobStatus1"] = "failed"
|
|
118
|
+
var_map[":jobStatus2"] = "merging"
|
|
119
|
+
var_map[":destinationDBlock"] = destination_block
|
|
120
|
+
statC, resC = taskBuffer.querySQLS(sqlC, var_map)
|
|
121
|
+
# finalize if all jobs have processed
|
|
122
|
+
if resC is not None:
|
|
123
|
+
num_unprocessed = resC[0][0]
|
|
124
|
+
tmp_log.debug(f"{num_unprocessed} unprocessed jobs")
|
|
125
|
+
if num_unprocessed == 0:
|
|
126
|
+
jobSpecs = taskBuffer.peekJobs(
|
|
127
|
+
[panda_id],
|
|
128
|
+
fromDefined=False,
|
|
129
|
+
fromArchived=False,
|
|
130
|
+
fromWaiting=False,
|
|
131
|
+
)
|
|
132
|
+
jobSpec = jobSpecs[0]
|
|
133
|
+
if jobSpec is None:
|
|
134
|
+
tmp_log.debug(f"skip PandaID={panda_id} not found in jobsActive")
|
|
135
|
+
continue
|
|
136
|
+
if jobSpec.produceUnMerge():
|
|
137
|
+
# collect sub datasets
|
|
138
|
+
sub_ds_names = set()
|
|
139
|
+
sub_ds_list = []
|
|
140
|
+
killed_for_bad_record = False
|
|
141
|
+
for tmpFileSpec in jobSpec.Files:
|
|
142
|
+
if tmpFileSpec.type in ["log", "output"] and re.search("_sub\d+$", tmpFileSpec.destinationDBlock) is not None:
|
|
143
|
+
if tmpFileSpec.destinationDBlock in sub_ds_names:
|
|
144
|
+
continue
|
|
145
|
+
sub_ds_names.add(tmpFileSpec.destinationDBlock)
|
|
146
|
+
datasetSpec = taskBuffer.queryDatasetWithMap({"name": tmpFileSpec.destinationDBlock})
|
|
147
|
+
# kill jobs since sub dataset is missing due to failures in setupper etc
|
|
148
|
+
if datasetSpec is None:
|
|
149
|
+
tmp_log.debug(f"sub dataset {tmpFileSpec.destinationDBlock} is missing")
|
|
150
|
+
sql_missing = "SELECT PandaID FROM ATLAS_PANDA.filesTable4 WHERE destinationDBlock=:destinationDBlock "
|
|
151
|
+
var_map = {":destinationDBlock": tmpFileSpec.destinationDBlock}
|
|
152
|
+
_, res_missing = taskBuffer.querySQLS(sql_missing, var_map)
|
|
153
|
+
missing_ids = [p for p, in res_missing]
|
|
154
|
+
tmp_log.debug(f"missing {tmpFileSpec.destinationDBlock} to kill {missing_ids}")
|
|
155
|
+
Client.kill_jobs(missing_ids, 2)
|
|
156
|
+
killed_for_bad_record = True
|
|
157
|
+
break
|
|
158
|
+
elif datasetSpec.status == "deleted":
|
|
159
|
+
tmp_log.debug(f"sub dataset {tmpFileSpec.destinationDBlock} is deleted")
|
|
160
|
+
sql_deleted = (
|
|
161
|
+
"SELECT j.PandaID "
|
|
162
|
+
"FROM ATLAS_PANDA.jobsActive4 j, ATLAS_PANDA.filesTable4 f "
|
|
163
|
+
"WHERE j.PandaID=f.PandaID AND j.jobStatus=:jobStatus "
|
|
164
|
+
"AND f.destinationDBlock=:destinationDBlock "
|
|
165
|
+
)
|
|
166
|
+
var_map = {":jobStatus": "merging", ":destinationDBlock": tmpFileSpec.destinationDBlock}
|
|
167
|
+
_, res_deleted = taskBuffer.querySQLS(sql_deleted, var_map)
|
|
168
|
+
deleted_ids = [p for p, in res_deleted]
|
|
169
|
+
tmp_log.debug(f"deleted {tmpFileSpec.destinationDBlock} to kill {deleted_ids}")
|
|
170
|
+
Client.kill_jobs(deleted_ids, 2)
|
|
171
|
+
killed_for_bad_record = True
|
|
172
|
+
break
|
|
173
|
+
else:
|
|
174
|
+
sub_ds_list.append(datasetSpec)
|
|
175
|
+
# update unmerged datasets to trigger merge job generation
|
|
176
|
+
if not killed_for_bad_record and sub_ds_list:
|
|
177
|
+
# check dataset status
|
|
178
|
+
all_defined = True
|
|
179
|
+
for datasetSpec in sub_ds_list:
|
|
180
|
+
if datasetSpec.status != "defined":
|
|
181
|
+
all_defined = False
|
|
182
|
+
tmp_log.debug(f"skip to update unmerged datasets since {datasetSpec.name} is {datasetSpec.status}")
|
|
183
|
+
break
|
|
184
|
+
if all_defined:
|
|
185
|
+
tmp_log.debug(f"update unmerged datasets {[d.name for d in sub_ds_list]}")
|
|
186
|
+
taskBuffer.updateUnmergedDatasets(jobSpec, sub_ds_list)
|
|
187
|
+
else:
|
|
188
|
+
tmp_log.debug("number of unprocessed jobs unknown")
|
|
189
|
+
except Exception as e:
|
|
190
|
+
_logger.error(f"Kick merging failed with {str(e)} {traceback.format_exc()}")
|
|
191
|
+
|
|
192
|
+
# finalize failed jobs
|
|
193
|
+
_logger.debug("check stuck merging jobs")
|
|
194
|
+
try:
|
|
195
|
+
timeLimit = naive_utcnow() - datetime.timedelta(hours=2)
|
|
196
|
+
# get PandaIDs
|
|
197
|
+
var_map = {}
|
|
198
|
+
var_map[":prodSourceLabel"] = "managed"
|
|
199
|
+
var_map[":jobStatus"] = "merging"
|
|
200
|
+
var_map[":timeLimit"] = timeLimit
|
|
201
|
+
sql = "SELECT distinct jediTaskID FROM ATLAS_PANDA.jobsActive4 "
|
|
202
|
+
sql += "WHERE prodSourceLabel=:prodSourceLabel AND jobStatus=:jobStatus and modificationTime<:timeLimit "
|
|
203
|
+
tmp, res = taskBuffer.querySQLS(sql, var_map)
|
|
204
|
+
|
|
205
|
+
for (jediTaskID,) in res:
|
|
206
|
+
var_map = {}
|
|
207
|
+
var_map[":jediTaskID"] = jediTaskID
|
|
208
|
+
var_map[":dsType"] = "trn_log"
|
|
209
|
+
sql = "SELECT datasetID FROM ATLAS_PANDA.JEDI_Datasets WHERE jediTaskID=:jediTaskID AND type=:dsType AND nFilesUsed=nFilesTobeUsed "
|
|
210
|
+
tmpP, resD = taskBuffer.querySQLS(sql, var_map)
|
|
211
|
+
for (datasetID,) in resD:
|
|
212
|
+
var_map = {}
|
|
213
|
+
var_map[":jediTaskID"] = jediTaskID
|
|
214
|
+
var_map[":fileStatus"] = "ready"
|
|
215
|
+
var_map[":datasetID"] = datasetID
|
|
216
|
+
sql = "SELECT PandaID FROM ATLAS_PANDA.JEDI_Dataset_Contents "
|
|
217
|
+
sql += "WHERE jediTaskID=:jediTaskID AND datasetid=:datasetID AND status=:fileStatus AND PandaID=OutPandaID AND rownum<=1 "
|
|
218
|
+
tmpP, resP = taskBuffer.querySQLS(sql, var_map)
|
|
219
|
+
if resP == []:
|
|
220
|
+
continue
|
|
221
|
+
PandaID = resP[0][0]
|
|
222
|
+
var_map = {}
|
|
223
|
+
var_map[":PandaID"] = PandaID
|
|
224
|
+
var_map[":fileType"] = "log"
|
|
225
|
+
sql = "SELECT d.status FROM ATLAS_PANDA.filesTable4 f,ATLAS_PANDA.datasets d WHERE PandaID=:PandaID AND f.type=:fileType AND d.name=f.destinationDBlock "
|
|
226
|
+
tmpS, resS = taskBuffer.querySQLS(sql, var_map)
|
|
227
|
+
if resS is not None:
|
|
228
|
+
(subStatus,) = resS[0]
|
|
229
|
+
if subStatus in ["completed"]:
|
|
230
|
+
jobSpecs = taskBuffer.peekJobs(
|
|
231
|
+
[PandaID],
|
|
232
|
+
fromDefined=False,
|
|
233
|
+
fromArchived=False,
|
|
234
|
+
fromWaiting=False,
|
|
235
|
+
)
|
|
236
|
+
jobSpec = jobSpecs[0]
|
|
237
|
+
sub_ds_names = set()
|
|
238
|
+
sub_ds_list = []
|
|
239
|
+
for tmpFileSpec in jobSpec.Files:
|
|
240
|
+
if tmpFileSpec.type in ["log", "output"] and re.search("_sub\d+$", tmpFileSpec.destinationDBlock) is not None:
|
|
241
|
+
if tmpFileSpec.destinationDBlock in sub_ds_names:
|
|
242
|
+
continue
|
|
243
|
+
sub_ds_names.add(tmpFileSpec.destinationDBlock)
|
|
244
|
+
datasetSpec = taskBuffer.queryDatasetWithMap({"name": tmpFileSpec.destinationDBlock})
|
|
245
|
+
sub_ds_list.append(datasetSpec)
|
|
246
|
+
_logger.debug(f"update unmerged datasets for jediTaskID={jediTaskID} PandaID={PandaID}")
|
|
247
|
+
taskBuffer.updateUnmergedDatasets(jobSpec, sub_ds_list, updateCompleted=True)
|
|
248
|
+
except Exception:
|
|
249
|
+
errType, errValue = sys.exc_info()[:2]
|
|
250
|
+
_logger.error(f"check for stuck merging jobs failed with {errType} {errValue}")
|
|
251
|
+
|
|
252
|
+
# get sites to skip various timeout
|
|
253
|
+
var_map = {}
|
|
254
|
+
var_map[":status"] = "paused"
|
|
255
|
+
sql = "SELECT /* use_json_type */ panda_queue FROM ATLAS_PANDA.schedconfig_json scj WHERE scj.data.status=:status "
|
|
256
|
+
sitesToSkipTO = set()
|
|
257
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
258
|
+
for (siteid,) in res:
|
|
259
|
+
sitesToSkipTO.add(siteid)
|
|
260
|
+
_logger.debug(f"PQs to skip timeout : {','.join(sitesToSkipTO)}")
|
|
261
|
+
|
|
262
|
+
sitesToDisableReassign = set()
|
|
263
|
+
# get sites to disable reassign
|
|
264
|
+
for siteName in siteMapper.siteSpecList:
|
|
265
|
+
siteSpec = siteMapper.siteSpecList[siteName]
|
|
266
|
+
if siteSpec.capability == "ucore" and not siteSpec.is_unified:
|
|
267
|
+
continue
|
|
268
|
+
if siteSpec.disable_reassign():
|
|
269
|
+
sitesToDisableReassign.add(siteName)
|
|
270
|
+
_logger.debug(f"PQs to disable reassign : {','.join(sitesToDisableReassign)}")
|
|
271
|
+
|
|
272
|
+
_memoryCheck("watcher")
|
|
273
|
+
|
|
274
|
+
_logger.debug("Watcher session")
|
|
275
|
+
|
|
276
|
+
# get the list of workflows
|
|
277
|
+
sql = "SELECT /* use_json_type */ DISTINCT scj.data.workflow FROM ATLAS_PANDA.schedconfig_json scj WHERE scj.data.status='online' "
|
|
278
|
+
status, res = taskBuffer.querySQLS(sql, {})
|
|
279
|
+
workflow_timeout_map = {}
|
|
280
|
+
for (workflow,) in res + [("production",), ("analysis",)]:
|
|
281
|
+
timeout = taskBuffer.getConfigValue("watcher", f"HEARTBEAT_TIMEOUT_{workflow}", "pandaserver", "atlas")
|
|
282
|
+
if timeout is not None:
|
|
283
|
+
workflow_timeout_map[workflow] = timeout
|
|
284
|
+
elif workflow in ["production", "analysis"]:
|
|
285
|
+
workflow_timeout_map[workflow] = 2
|
|
286
|
+
|
|
287
|
+
workflows = list(workflow_timeout_map)
|
|
288
|
+
|
|
289
|
+
_logger.debug(f"timeout : {str(workflow_timeout_map)}")
|
|
290
|
+
|
|
291
|
+
# check heartbeat for analysis jobs
|
|
292
|
+
timeLimit = naive_utcnow() - datetime.timedelta(hours=workflow_timeout_map["analysis"])
|
|
293
|
+
var_map = {}
|
|
294
|
+
var_map[":modificationTime"] = timeLimit
|
|
295
|
+
var_map[":prodSourceLabel1"] = "panda"
|
|
296
|
+
var_map[":prodSourceLabel2"] = "user"
|
|
297
|
+
var_map[":jobStatus1"] = "running"
|
|
298
|
+
var_map[":jobStatus2"] = "starting"
|
|
299
|
+
var_map[":jobStatus3"] = "stagein"
|
|
300
|
+
var_map[":jobStatus4"] = "stageout"
|
|
301
|
+
sql = "SELECT PandaID FROM ATLAS_PANDA.jobsActive4 WHERE (prodSourceLabel=:prodSourceLabel1 OR prodSourceLabel=:prodSourceLabel2) "
|
|
302
|
+
sql += "AND jobStatus IN (:jobStatus1,:jobStatus2,:jobStatus3,:jobStatus4) AND modificationTime<:modificationTime"
|
|
303
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
304
|
+
if res is None:
|
|
305
|
+
_logger.debug(f"# of Anal Watcher : {res}")
|
|
306
|
+
else:
|
|
307
|
+
_logger.debug(f"# of Anal Watcher : {len(res)}")
|
|
308
|
+
for (id,) in res:
|
|
309
|
+
_logger.debug(f"Anal Watcher {id}")
|
|
310
|
+
thr = Watcher(taskBuffer, id, single=True, sleepTime=60, sitemapper=siteMapper)
|
|
311
|
+
thr.start()
|
|
312
|
+
thr.join()
|
|
313
|
+
|
|
314
|
+
# check heartbeat for analysis jobs in transferring
|
|
315
|
+
timeLimit = naive_utcnow() - datetime.timedelta(hours=workflow_timeout_map["analysis"])
|
|
316
|
+
var_map = {}
|
|
317
|
+
var_map[":modificationTime"] = timeLimit
|
|
318
|
+
var_map[":prodSourceLabel1"] = "panda"
|
|
319
|
+
var_map[":prodSourceLabel2"] = "user"
|
|
320
|
+
var_map[":jobStatus1"] = "transferring"
|
|
321
|
+
sql = "SELECT PandaID FROM ATLAS_PANDA.jobsActive4 WHERE prodSourceLabel IN (:prodSourceLabel1,:prodSourceLabel2) "
|
|
322
|
+
sql += "AND jobStatus=:jobStatus1 AND modificationTime<:modificationTime"
|
|
323
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
324
|
+
if res is None:
|
|
325
|
+
_logger.debug(f"# of Transferring Anal Watcher : {res}")
|
|
326
|
+
else:
|
|
327
|
+
_logger.debug(f"# of Transferring Anal Watcher : {len(res)}")
|
|
328
|
+
for (id,) in res:
|
|
329
|
+
_logger.debug(f"Trans Anal Watcher {id}")
|
|
330
|
+
thr = Watcher(taskBuffer, id, single=True, sleepTime=60, sitemapper=siteMapper)
|
|
331
|
+
thr.start()
|
|
332
|
+
thr.join()
|
|
333
|
+
|
|
334
|
+
# check heartbeat for sent jobs
|
|
335
|
+
timeLimit = naive_utcnow() - datetime.timedelta(minutes=30)
|
|
336
|
+
var_map = {}
|
|
337
|
+
var_map[":jobStatus"] = "sent"
|
|
338
|
+
var_map[":modificationTime"] = timeLimit
|
|
339
|
+
status, res = taskBuffer.querySQLS(
|
|
340
|
+
"SELECT PandaID FROM ATLAS_PANDA.jobsActive4 WHERE jobStatus=:jobStatus AND modificationTime<:modificationTime",
|
|
341
|
+
var_map,
|
|
342
|
+
)
|
|
343
|
+
if res is None:
|
|
344
|
+
_logger.debug(f"# of Sent Watcher : {res}")
|
|
345
|
+
else:
|
|
346
|
+
_logger.debug(f"# of Sent Watcher : {len(res)}")
|
|
347
|
+
for (id,) in res:
|
|
348
|
+
_logger.debug(f"Sent Watcher {id}")
|
|
349
|
+
thr = Watcher(taskBuffer, id, single=True, sleepTime=30, sitemapper=siteMapper)
|
|
350
|
+
thr.start()
|
|
351
|
+
thr.join()
|
|
352
|
+
|
|
353
|
+
# check heartbeat for 'holding' analysis/ddm jobs
|
|
354
|
+
timeLimit = naive_utcnow() - datetime.timedelta(hours=3)
|
|
355
|
+
# get XMLs
|
|
356
|
+
xmlIDs = set()
|
|
357
|
+
# xmlFiles = os.listdir(panda_config.logdir)
|
|
358
|
+
# for file in xmlFiles:
|
|
359
|
+
# match = re.search('^(\d+)_([^_]+)_.{36}$',file)
|
|
360
|
+
# if match is not None:
|
|
361
|
+
# id = match.group(1)
|
|
362
|
+
# xmlIDs.append(int(id))
|
|
363
|
+
job_output_report_list = taskBuffer.listJobOutputReport()
|
|
364
|
+
if job_output_report_list is not None:
|
|
365
|
+
for panda_id, job_status, attempt_nr, time_stamp in job_output_report_list:
|
|
366
|
+
xmlIDs.add(int(panda_id))
|
|
367
|
+
sql = "SELECT PandaID FROM ATLAS_PANDA.jobsActive4 WHERE jobStatus=:jobStatus AND (modificationTime<:modificationTime OR (endTime IS NOT NULL AND endTime<:endTime)) AND (prodSourceLabel=:prodSourceLabel1 OR prodSourceLabel=:prodSourceLabel2) AND stateChangeTime != modificationTime"
|
|
368
|
+
var_map = {}
|
|
369
|
+
var_map[":modificationTime"] = timeLimit
|
|
370
|
+
var_map[":endTime"] = timeLimit
|
|
371
|
+
var_map[":jobStatus"] = "holding"
|
|
372
|
+
var_map[":prodSourceLabel1"] = "panda"
|
|
373
|
+
var_map[":prodSourceLabel2"] = "user"
|
|
374
|
+
|
|
375
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
376
|
+
if res is None:
|
|
377
|
+
_logger.debug(f"# of Holding Anal/DDM Watcher : {res}")
|
|
378
|
+
else:
|
|
379
|
+
_logger.debug(f"# of Holding Anal/DDM Watcher : {len(res)} - XMLs : {len(xmlIDs)}")
|
|
380
|
+
for (id,) in res:
|
|
381
|
+
_logger.debug(f"Holding Anal/DDM Watcher {id}")
|
|
382
|
+
if int(id) in xmlIDs:
|
|
383
|
+
_logger.debug(f" found XML -> skip {id}")
|
|
384
|
+
continue
|
|
385
|
+
thr = Watcher(taskBuffer, id, single=True, sleepTime=180, sitemapper=siteMapper)
|
|
386
|
+
thr.start()
|
|
387
|
+
thr.join()
|
|
388
|
+
|
|
389
|
+
# check heartbeat for high prio production jobs
|
|
390
|
+
timeOutVal = 3
|
|
391
|
+
timeLimit = naive_utcnow() - datetime.timedelta(hours=timeOutVal)
|
|
392
|
+
sql = "SELECT PandaID FROM ATLAS_PANDA.jobsActive4 WHERE jobStatus=:jobStatus AND currentPriority>:pLimit "
|
|
393
|
+
sql += "AND (modificationTime<:modificationTime OR (endTime IS NOT NULL AND endTime<:endTime))"
|
|
394
|
+
var_map = {}
|
|
395
|
+
var_map[":modificationTime"] = timeLimit
|
|
396
|
+
var_map[":endTime"] = timeLimit
|
|
397
|
+
var_map[":jobStatus"] = "holding"
|
|
398
|
+
var_map[":pLimit"] = 800
|
|
399
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
400
|
+
if res is None:
|
|
401
|
+
_logger.debug(f"# of High prio Holding Watcher : {res}")
|
|
402
|
+
else:
|
|
403
|
+
_logger.debug(f"# of High prio Holding Watcher : {len(res)}")
|
|
404
|
+
for (id,) in res:
|
|
405
|
+
_logger.debug(f"High prio Holding Watcher {id}")
|
|
406
|
+
thr = Watcher(
|
|
407
|
+
taskBuffer,
|
|
408
|
+
id,
|
|
409
|
+
single=True,
|
|
410
|
+
sleepTime=60 * timeOutVal,
|
|
411
|
+
sitemapper=siteMapper,
|
|
412
|
+
)
|
|
413
|
+
thr.start()
|
|
414
|
+
thr.join()
|
|
415
|
+
|
|
416
|
+
# check heartbeat for production jobs
|
|
417
|
+
timeOutVal = taskBuffer.getConfigValue("job_timeout", "TIMEOUT_holding", "pandaserver")
|
|
418
|
+
if not timeOutVal:
|
|
419
|
+
timeOutVal = 48
|
|
420
|
+
timeOutVal *= 60
|
|
421
|
+
timeLimit = naive_utcnow() - datetime.timedelta(minutes=timeOutVal)
|
|
422
|
+
sql = "SELECT PandaID FROM ATLAS_PANDA.jobsActive4 WHERE jobStatus=:jobStatus AND (modificationTime<:modificationTime OR (endTime IS NOT NULL AND endTime<:endTime))"
|
|
423
|
+
var_map = {}
|
|
424
|
+
var_map[":modificationTime"] = timeLimit
|
|
425
|
+
var_map[":endTime"] = timeLimit
|
|
426
|
+
var_map[":jobStatus"] = "holding"
|
|
427
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
428
|
+
if res is None:
|
|
429
|
+
_logger.debug(f"# of Holding Watcher with timeout {timeOutVal}min: {str(res)}")
|
|
430
|
+
else:
|
|
431
|
+
_logger.debug(f"# of Holding Watcher with timeout {timeOutVal}min: {len(res)}")
|
|
432
|
+
for (id,) in res:
|
|
433
|
+
_logger.debug(f"Holding Watcher {id}")
|
|
434
|
+
thr = Watcher(taskBuffer, id, single=True, sleepTime=timeOutVal, sitemapper=siteMapper)
|
|
435
|
+
thr.start()
|
|
436
|
+
thr.join()
|
|
437
|
+
|
|
438
|
+
# check heartbeat for production jobs
|
|
439
|
+
sql = (
|
|
440
|
+
"SELECT /* use_json_type */ PandaID, jobStatus, j.computingSite FROM ATLAS_PANDA.jobsActive4 j "
|
|
441
|
+
"LEFT JOIN ATLAS_PANDA.schedconfig_json s ON j.computingSite=s.panda_queue "
|
|
442
|
+
"WHERE jobStatus IN (:jobStatus1,:jobStatus2,:jobStatus3,:jobStatus4) "
|
|
443
|
+
"AND modificationTime<:modificationTime "
|
|
444
|
+
)
|
|
445
|
+
for workflow in workflows:
|
|
446
|
+
if workflow == "analysis":
|
|
447
|
+
continue
|
|
448
|
+
var_map = {}
|
|
449
|
+
var_map[":jobStatus1"] = "running"
|
|
450
|
+
var_map[":jobStatus2"] = "starting"
|
|
451
|
+
var_map[":jobStatus3"] = "stagein"
|
|
452
|
+
var_map[":jobStatus4"] = "stageout"
|
|
453
|
+
sqlX = sql
|
|
454
|
+
if workflow == "production":
|
|
455
|
+
if len(workflows) > 2:
|
|
456
|
+
ng_workflow_var_names_str, ng_workflow_var_map = get_sql_IN_bind_variables(workflows, prefix=":w_", value_as_suffix=True)
|
|
457
|
+
sqlX += f"AND (s.data.workflow IS NULL OR s.data.workflow NOT IN ({ng_workflow_var_names_str})) "
|
|
458
|
+
var_map.update(ng_workflow_var_map)
|
|
459
|
+
else:
|
|
460
|
+
tmp_key = f":w_{workflow}"
|
|
461
|
+
sqlX += f"AND s.data.workflow={tmp_key} "
|
|
462
|
+
var_map[tmp_key] = workflow
|
|
463
|
+
timeOutVal = workflow_timeout_map[workflow]
|
|
464
|
+
timeLimit = naive_utcnow() - datetime.timedelta(hours=timeOutVal)
|
|
465
|
+
var_map[":modificationTime"] = timeLimit
|
|
466
|
+
status, res = taskBuffer.querySQLS(sqlX, var_map)
|
|
467
|
+
if res is None:
|
|
468
|
+
_logger.debug(f"# of General Watcher with workflow={workflow}: {res}")
|
|
469
|
+
else:
|
|
470
|
+
_logger.debug(f"# of General Watcher with workflow={workflow}: {len(res)}")
|
|
471
|
+
for pandaID, jobStatus, computingSite in res:
|
|
472
|
+
if computingSite in sitesToSkipTO:
|
|
473
|
+
_logger.debug(f"skip General Watcher for PandaID={pandaID} at {computingSite} since timeout is disabled for {jobStatus}")
|
|
474
|
+
continue
|
|
475
|
+
_logger.debug(f"General Watcher {pandaID}")
|
|
476
|
+
thr = Watcher(
|
|
477
|
+
taskBuffer,
|
|
478
|
+
pandaID,
|
|
479
|
+
single=True,
|
|
480
|
+
sleepTime=60 * timeOutVal,
|
|
481
|
+
sitemapper=siteMapper,
|
|
482
|
+
)
|
|
483
|
+
thr.start()
|
|
484
|
+
thr.join()
|
|
485
|
+
|
|
486
|
+
_memoryCheck("reassign")
|
|
487
|
+
|
|
488
|
+
# kill long-waiting jobs in defined table
|
|
489
|
+
timeLimit = naive_utcnow() - datetime.timedelta(days=7)
|
|
490
|
+
status, res = taskBuffer.querySQLS(
|
|
491
|
+
"SELECT PandaID,cloud,prodSourceLabel FROM ATLAS_PANDA.jobsDefined4 WHERE creationTime<:creationTime",
|
|
492
|
+
{":creationTime": timeLimit},
|
|
493
|
+
)
|
|
494
|
+
jobs = []
|
|
495
|
+
dashFileMap = {}
|
|
496
|
+
if res is not None:
|
|
497
|
+
for pandaID, cloud, prodSourceLabel in res:
|
|
498
|
+
# collect PandaIDs
|
|
499
|
+
jobs.append(pandaID)
|
|
500
|
+
if len(jobs):
|
|
501
|
+
_logger.debug(f"killJobs for Defined ({str(jobs)})")
|
|
502
|
+
Client.kill_jobs(jobs, 2)
|
|
503
|
+
|
|
504
|
+
# kill long-waiting jobs in active table
|
|
505
|
+
timeLimit = naive_utcnow() - datetime.timedelta(days=7)
|
|
506
|
+
var_map = {}
|
|
507
|
+
var_map[":jobStatus"] = "activated"
|
|
508
|
+
var_map[":creationTime"] = timeLimit
|
|
509
|
+
status, res = taskBuffer.querySQLS(
|
|
510
|
+
"SELECT PandaID from ATLAS_PANDA.jobsActive4 WHERE jobStatus=:jobStatus AND creationTime<:creationTime",
|
|
511
|
+
var_map,
|
|
512
|
+
)
|
|
513
|
+
jobs = []
|
|
514
|
+
if res is not None:
|
|
515
|
+
for (id,) in res:
|
|
516
|
+
jobs.append(id)
|
|
517
|
+
if len(jobs):
|
|
518
|
+
_logger.debug(f"killJobs for Active ({str(jobs)})")
|
|
519
|
+
Client.kill_jobs(jobs, 2)
|
|
520
|
+
|
|
521
|
+
# fast rebrokerage at PQs where Nq/Nr overshoots
|
|
522
|
+
_logger.debug("fast rebrokerage at PQs where Nq/Nr overshoots")
|
|
523
|
+
try:
|
|
524
|
+
ratioLimit = taskBuffer.getConfigValue("rebroker", "FAST_REBRO_THRESHOLD_NQNR_RATIO")
|
|
525
|
+
fractionLimit = taskBuffer.getConfigValue("rebroker", "FAST_REBRO_THRESHOLD_NQUEUE_FRAC")
|
|
526
|
+
if not ratioLimit:
|
|
527
|
+
ratioLimit = 3
|
|
528
|
+
if not fractionLimit:
|
|
529
|
+
fractionLimit = 0.3
|
|
530
|
+
|
|
531
|
+
# get overloaded PQs
|
|
532
|
+
sql = (
|
|
533
|
+
"SELECT COMPUTINGSITE,JOBSTATUS,GSHARE,SUM(NJOBS) FROM ATLAS_PANDA.{} "
|
|
534
|
+
"WHERE workqueue_id NOT IN "
|
|
535
|
+
"(SELECT queue_id FROM ATLAS_PANDA.jedi_work_queue WHERE queue_function = 'Resource') "
|
|
536
|
+
"AND computingsite NOT IN "
|
|
537
|
+
"(SELECT pandaqueuename FROM ATLAS_PANDA.HARVESTER_Slots) GROUP BY COMPUTINGSITE,JOBSTATUS,GSHARE "
|
|
538
|
+
)
|
|
539
|
+
|
|
540
|
+
statsPerShare = {}
|
|
541
|
+
statsPerPQ = {}
|
|
542
|
+
for table in ["JOBS_SHARE_STATS", "JOBSDEFINED_SHARE_STATS"]:
|
|
543
|
+
status, res = taskBuffer.querySQLS(sql.format(table), {})
|
|
544
|
+
for computingSite, jobStatus, gshare, nJobs in res:
|
|
545
|
+
statsPerShare.setdefault(gshare, {"nq": 0, "nr": 0})
|
|
546
|
+
statsPerPQ.setdefault(computingSite, {})
|
|
547
|
+
statsPerPQ[computingSite].setdefault(gshare, {"nq": 0, "nr": 0})
|
|
548
|
+
if jobStatus in ["defined", "assigned", "activated", "starting"]:
|
|
549
|
+
statsPerPQ[computingSite][gshare]["nq"] += nJobs
|
|
550
|
+
statsPerShare[gshare]["nq"] += nJobs
|
|
551
|
+
elif jobStatus == "running":
|
|
552
|
+
statsPerPQ[computingSite][gshare]["nr"] += nJobs
|
|
553
|
+
statsPerShare[gshare]["nr"] += nJobs
|
|
554
|
+
|
|
555
|
+
# check
|
|
556
|
+
sql = (
|
|
557
|
+
"SELECT * FROM ("
|
|
558
|
+
"SELECT * FROM ("
|
|
559
|
+
"SELECT PandaID FROM ATLAS_PANDA.jobsDefined4 "
|
|
560
|
+
"WHERE computingSite=:computingSite "
|
|
561
|
+
"AND gshare=:gshare AND jobStatus IN (:jobStatus1,:jobStatus2,:jobStatus3,:jobStatus4) "
|
|
562
|
+
"UNION "
|
|
563
|
+
"SELECT PandaID FROM ATLAS_PANDA.jobsActive4 "
|
|
564
|
+
"WHERE computingSite=:computingSite "
|
|
565
|
+
"AND gshare=:gshare AND jobStatus IN (:jobStatus1,:jobStatus2,:jobStatus3,:jobStatus4) "
|
|
566
|
+
") ORDER BY PandaID "
|
|
567
|
+
") WHERE rownum<:nRows "
|
|
568
|
+
)
|
|
569
|
+
nQueueLimitMap = {}
|
|
570
|
+
for computingSite, shareStat in statsPerPQ.items():
|
|
571
|
+
for gshare, nStat in shareStat.items():
|
|
572
|
+
# get limit
|
|
573
|
+
if gshare not in nQueueLimitMap:
|
|
574
|
+
key = f"FAST_REBRO_THRESHOLD_NQUEUE_{gshare}"
|
|
575
|
+
nQueueLimitMap[gshare] = taskBuffer.getConfigValue("rebroker", key)
|
|
576
|
+
nQueueLimit = nQueueLimitMap[gshare]
|
|
577
|
+
if not nQueueLimit:
|
|
578
|
+
dry_run = True
|
|
579
|
+
nQueueLimit = 10
|
|
580
|
+
else:
|
|
581
|
+
dry_run = False
|
|
582
|
+
ratioCheck = nStat["nr"] * ratioLimit < nStat["nq"]
|
|
583
|
+
statCheck = nStat["nq"] > nQueueLimit
|
|
584
|
+
fracCheck = nStat["nq"] > statsPerShare[gshare]["nq"] * fractionLimit
|
|
585
|
+
_logger.debug(
|
|
586
|
+
"{} in {} : nQueue({})>nRun({})*{}: {},"
|
|
587
|
+
" nQueue>nQueueThreshold({}):{}, nQueue>nQueue_total({})*{}:{}".format(
|
|
588
|
+
computingSite,
|
|
589
|
+
gshare,
|
|
590
|
+
nStat["nq"],
|
|
591
|
+
nStat["nr"],
|
|
592
|
+
ratioLimit,
|
|
593
|
+
ratioCheck,
|
|
594
|
+
nQueueLimit,
|
|
595
|
+
statCheck,
|
|
596
|
+
statsPerShare[gshare]["nq"],
|
|
597
|
+
fractionLimit,
|
|
598
|
+
fracCheck,
|
|
599
|
+
)
|
|
600
|
+
)
|
|
601
|
+
if ratioCheck and statCheck and fracCheck:
|
|
602
|
+
_logger.debug(f"{computingSite} overshoot in {gshare}")
|
|
603
|
+
if not dry_run:
|
|
604
|
+
# calculate excess
|
|
605
|
+
excess = min(
|
|
606
|
+
nStat["nq"] - nStat["nr"] * ratioLimit,
|
|
607
|
+
nStat["nq"] - nQueueLimit,
|
|
608
|
+
)
|
|
609
|
+
excess = min(
|
|
610
|
+
excess,
|
|
611
|
+
nStat["nq"] - statsPerShare[gshare]["nq"] * fractionLimit,
|
|
612
|
+
)
|
|
613
|
+
excess = int(math.ceil(excess))
|
|
614
|
+
var_map = {}
|
|
615
|
+
var_map[":computingSite"] = computingSite
|
|
616
|
+
var_map[":gshare"] = gshare
|
|
617
|
+
var_map[":jobStatus1"] = "defined"
|
|
618
|
+
var_map[":jobStatus2"] = "assigned"
|
|
619
|
+
var_map[":jobStatus3"] = "activated"
|
|
620
|
+
var_map[":jobStatus4"] = "starting"
|
|
621
|
+
var_map[":nRows"] = excess
|
|
622
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
623
|
+
jediJobs = [p for p, in res]
|
|
624
|
+
_logger.debug(f"got {len(jediJobs)} jobs to kill excess={excess}")
|
|
625
|
+
if jediJobs:
|
|
626
|
+
nJob = 100
|
|
627
|
+
iJob = 0
|
|
628
|
+
while iJob < len(jediJobs):
|
|
629
|
+
_logger.debug(f"reassignJobs for JEDI at Nq/Nr overshoot site {computingSite} ({str(jediJobs[iJob:iJob + nJob])})")
|
|
630
|
+
Client.kill_jobs(jediJobs[iJob : iJob + nJob], 10, keep_unmerged=True)
|
|
631
|
+
iJob += nJob
|
|
632
|
+
except Exception as e:
|
|
633
|
+
_logger.error(f"failed with {str(e)} {traceback.format_exc()}")
|
|
634
|
+
|
|
635
|
+
# reassign activated jobs in inactive sites
|
|
636
|
+
inactiveTimeLimitSite = 2
|
|
637
|
+
inactiveTimeLimitJob = 4
|
|
638
|
+
inactivePrioLimit = 800
|
|
639
|
+
timeLimitSite = naive_utcnow() - datetime.timedelta(hours=inactiveTimeLimitSite)
|
|
640
|
+
timeLimitJob = naive_utcnow() - datetime.timedelta(hours=inactiveTimeLimitJob)
|
|
641
|
+
# get PandaIDs
|
|
642
|
+
sql = "SELECT distinct computingSite FROM ATLAS_PANDA.jobsActive4 "
|
|
643
|
+
sql += "WHERE prodSourceLabel=:prodSourceLabel "
|
|
644
|
+
sql += "AND ((modificationTime<:timeLimit AND jobStatus=:jobStatus1) "
|
|
645
|
+
sql += "OR (stateChangeTime<:timeLimit AND jobStatus=:jobStatus2)) "
|
|
646
|
+
sql += "AND lockedby=:lockedby AND currentPriority>=:prioLimit "
|
|
647
|
+
sql += "AND NOT processingType IN (:pType1) AND relocationFlag<>:rFlag1 "
|
|
648
|
+
var_map = {}
|
|
649
|
+
var_map[":prodSourceLabel"] = "managed"
|
|
650
|
+
var_map[":jobStatus1"] = "activated"
|
|
651
|
+
var_map[":jobStatus2"] = "starting"
|
|
652
|
+
var_map[":lockedby"] = "jedi"
|
|
653
|
+
var_map[":timeLimit"] = timeLimitJob
|
|
654
|
+
var_map[":prioLimit"] = inactivePrioLimit
|
|
655
|
+
var_map[":pType1"] = "pmerge"
|
|
656
|
+
var_map[":rFlag1"] = 2
|
|
657
|
+
stDS, resDS = taskBuffer.querySQLS(sql, var_map)
|
|
658
|
+
sqlSS = "SELECT laststart FROM ATLAS_PANDAMETA.siteData "
|
|
659
|
+
sqlSS += "WHERE site=:site AND flag=:flag AND hours=:hours "
|
|
660
|
+
sqlPI = "SELECT PandaID,eventService,attemptNr FROM ATLAS_PANDA.jobsActive4 "
|
|
661
|
+
sqlPI += "WHERE prodSourceLabel=:prodSourceLabel AND jobStatus IN (:jobStatus1,:jobStatus2) "
|
|
662
|
+
sqlPI += "AND (modificationTime<:timeLimit OR stateChangeTime<:timeLimit) "
|
|
663
|
+
sqlPI += "AND lockedby=:lockedby AND currentPriority>=:prioLimit "
|
|
664
|
+
sqlPI += "AND computingSite=:site AND NOT processingType IN (:pType1) AND relocationFlag<>:rFlag1 "
|
|
665
|
+
for (tmpSite,) in resDS:
|
|
666
|
+
if tmpSite in sitesToDisableReassign:
|
|
667
|
+
_logger.debug(f"skip reassignJobs at inactive site {tmpSite} since reassign is disabled")
|
|
668
|
+
continue
|
|
669
|
+
# check if the site is inactive
|
|
670
|
+
var_map = {}
|
|
671
|
+
var_map[":site"] = tmpSite
|
|
672
|
+
var_map[":flag"] = "production"
|
|
673
|
+
var_map[":hours"] = 3
|
|
674
|
+
stSS, resSS = taskBuffer.querySQLS(sqlSS, var_map)
|
|
675
|
+
if resSS is not None and len(resSS) > 0:
|
|
676
|
+
last_start = resSS[0][0]
|
|
677
|
+
else:
|
|
678
|
+
last_start = None
|
|
679
|
+
site_status = siteMapper.getSite(tmpSite).status
|
|
680
|
+
if stSS is True and ((last_start is not None and last_start < timeLimitSite) or site_status in ["offline", "test"]):
|
|
681
|
+
# get jobs
|
|
682
|
+
var_map = {}
|
|
683
|
+
var_map[":prodSourceLabel"] = "managed"
|
|
684
|
+
var_map[":jobStatus1"] = "activated"
|
|
685
|
+
var_map[":jobStatus2"] = "starting"
|
|
686
|
+
var_map[":lockedby"] = "jedi"
|
|
687
|
+
var_map[":timeLimit"] = timeLimitJob
|
|
688
|
+
var_map[":prioLimit"] = inactivePrioLimit
|
|
689
|
+
var_map[":site"] = tmpSite
|
|
690
|
+
var_map[":pType1"] = "pmerge"
|
|
691
|
+
var_map[":rFlag1"] = 2
|
|
692
|
+
stPI, resPI = taskBuffer.querySQLS(sqlPI, var_map)
|
|
693
|
+
jediJobs = []
|
|
694
|
+
# reassign
|
|
695
|
+
_logger.debug(f"reassignJobs for JEDI at inactive site {tmpSite} laststart={last_start} status={site_status}")
|
|
696
|
+
if resPI is not None:
|
|
697
|
+
for pandaID, eventService, attemptNr in resPI:
|
|
698
|
+
if eventService in [EventServiceUtils.esMergeJobFlagNumber]:
|
|
699
|
+
_logger.debug(f"retrying es merge {pandaID} at inactive site {tmpSite}")
|
|
700
|
+
taskBuffer.retryJob(
|
|
701
|
+
pandaID,
|
|
702
|
+
{},
|
|
703
|
+
getNewPandaID=True,
|
|
704
|
+
attemptNr=attemptNr,
|
|
705
|
+
recoverableEsMerge=True,
|
|
706
|
+
)
|
|
707
|
+
jediJobs.append(pandaID)
|
|
708
|
+
if len(jediJobs) != 0:
|
|
709
|
+
nJob = 100
|
|
710
|
+
iJob = 0
|
|
711
|
+
while iJob < len(jediJobs):
|
|
712
|
+
_logger.debug(f"reassignJobs for JEDI at inactive site {tmpSite} ({jediJobs[iJob:iJob + nJob]})")
|
|
713
|
+
Client.kill_jobs(jediJobs[iJob : iJob + nJob], 51, keep_unmerged=True)
|
|
714
|
+
iJob += nJob
|
|
715
|
+
|
|
716
|
+
# reassign defined jobs in defined table
|
|
717
|
+
timeoutValue = taskBuffer.getConfigValue("job_timeout", "TIMEOUT_defined", "pandaserver")
|
|
718
|
+
if not timeoutValue:
|
|
719
|
+
timeoutValue = 4
|
|
720
|
+
timeoutValue *= 60
|
|
721
|
+
timeLimit = naive_utcnow() - datetime.timedelta(minutes=timeoutValue)
|
|
722
|
+
# get PandaIDs
|
|
723
|
+
status, res = taskBuffer.lockJobsForReassign(
|
|
724
|
+
"ATLAS_PANDA.jobsDefined4",
|
|
725
|
+
timeLimit,
|
|
726
|
+
["defined"],
|
|
727
|
+
["managed", "test"],
|
|
728
|
+
[],
|
|
729
|
+
[],
|
|
730
|
+
[],
|
|
731
|
+
True,
|
|
732
|
+
)
|
|
733
|
+
jediJobs = []
|
|
734
|
+
if res is not None:
|
|
735
|
+
for id, lockedby in res:
|
|
736
|
+
if lockedby == "jedi":
|
|
737
|
+
jediJobs.append(id)
|
|
738
|
+
|
|
739
|
+
# reassign
|
|
740
|
+
_logger.debug(f"reassignJobs for JEDI defined jobs -> #{len(jediJobs)}")
|
|
741
|
+
if len(jediJobs) != 0:
|
|
742
|
+
nJob = 100
|
|
743
|
+
iJob = 0
|
|
744
|
+
while iJob < len(jediJobs):
|
|
745
|
+
_logger.debug(f"reassignJobs for JEDI defined jobs ({jediJobs[iJob:iJob + nJob]})")
|
|
746
|
+
Client.kill_jobs(jediJobs[iJob : iJob + nJob], 51, keep_unmerged=True)
|
|
747
|
+
iJob += nJob
|
|
748
|
+
|
|
749
|
+
# reassign stalled defined build and non-JEDI jobs
|
|
750
|
+
timeLimit = naive_utcnow() - datetime.timedelta(minutes=timeoutValue)
|
|
751
|
+
var_map = {}
|
|
752
|
+
var_map[":jobStatus"] = "defined"
|
|
753
|
+
var_map[":prodSourceLabel_p"] = "panda"
|
|
754
|
+
var_map[":timeLimit"] = timeLimit
|
|
755
|
+
status, res = taskBuffer.querySQLS(
|
|
756
|
+
"SELECT PandaID FROM ATLAS_PANDA.jobsDefined4 WHERE ((prodSourceLabel=:prodSourceLabel_p AND transformation LIKE '%build%') OR "
|
|
757
|
+
"lockedBy IS NULL) AND jobStatus=:jobStatus AND creationTime<:timeLimit ORDER BY PandaID",
|
|
758
|
+
var_map,
|
|
759
|
+
)
|
|
760
|
+
jobs = []
|
|
761
|
+
if res is not None:
|
|
762
|
+
for (id,) in res:
|
|
763
|
+
jobs.append(id)
|
|
764
|
+
# kill
|
|
765
|
+
if len(jobs):
|
|
766
|
+
Client.kill_jobs(jobs, 2)
|
|
767
|
+
_logger.debug(f"reassign stalled defined build and non-JEDI jobs with timeout {timeoutValue}min ({str(jobs)})")
|
|
768
|
+
|
|
769
|
+
# reassign long-waiting jobs in defined table
|
|
770
|
+
timeLimit = naive_utcnow() - datetime.timedelta(hours=12)
|
|
771
|
+
status, res = taskBuffer.lockJobsForReassign("ATLAS_PANDA.jobsDefined4", timeLimit, [], ["managed"], [], [], [], True)
|
|
772
|
+
jediJobs = []
|
|
773
|
+
if res is not None:
|
|
774
|
+
for id, lockedby in res:
|
|
775
|
+
if lockedby == "jedi":
|
|
776
|
+
jediJobs.append(id)
|
|
777
|
+
else:
|
|
778
|
+
jobs.append(id)
|
|
779
|
+
# reassign
|
|
780
|
+
_logger.debug(f"reassignJobs for long JEDI in defined table -> #{len(jediJobs)}")
|
|
781
|
+
if len(jediJobs) != 0:
|
|
782
|
+
nJob = 100
|
|
783
|
+
iJob = 0
|
|
784
|
+
while iJob < len(jediJobs):
|
|
785
|
+
_logger.debug(f"reassignJobs for long JEDI in defined table ({jediJobs[iJob:iJob + nJob]})")
|
|
786
|
+
Client.kill_jobs(jediJobs[iJob : iJob + nJob], 51, keep_unmerged=True)
|
|
787
|
+
iJob += nJob
|
|
788
|
+
|
|
789
|
+
# reassign too long activated jobs in active table
|
|
790
|
+
timeLimit = naive_utcnow() - datetime.timedelta(days=2)
|
|
791
|
+
status, res = taskBuffer.lockJobsForReassign(
|
|
792
|
+
"ATLAS_PANDA.jobsActive4",
|
|
793
|
+
timeLimit,
|
|
794
|
+
["activated"],
|
|
795
|
+
["managed"],
|
|
796
|
+
[],
|
|
797
|
+
[],
|
|
798
|
+
[],
|
|
799
|
+
True,
|
|
800
|
+
onlyReassignable=True,
|
|
801
|
+
getEventService=True,
|
|
802
|
+
)
|
|
803
|
+
jediJobs = []
|
|
804
|
+
if res is not None:
|
|
805
|
+
for pandaID, lockedby, eventService, attemptNr, computingSite in res:
|
|
806
|
+
if computingSite in sitesToDisableReassign:
|
|
807
|
+
_logger.debug(f"skip reassignJobs for long activated PandaID={pandaID} since disabled at {computingSite}")
|
|
808
|
+
continue
|
|
809
|
+
if lockedby == "jedi":
|
|
810
|
+
if eventService in [EventServiceUtils.esMergeJobFlagNumber]:
|
|
811
|
+
_logger.debug("retrying {0} in long activated" % pandaID)
|
|
812
|
+
taskBuffer.retryJob(
|
|
813
|
+
pandaID,
|
|
814
|
+
{},
|
|
815
|
+
getNewPandaID=True,
|
|
816
|
+
attemptNr=attemptNr,
|
|
817
|
+
recoverableEsMerge=True,
|
|
818
|
+
)
|
|
819
|
+
jediJobs.append(pandaID)
|
|
820
|
+
|
|
821
|
+
_logger.debug(f"reassignJobs for long activated JEDI in active table -> #{len(jediJobs)}")
|
|
822
|
+
if len(jediJobs) != 0:
|
|
823
|
+
nJob = 100
|
|
824
|
+
iJob = 0
|
|
825
|
+
while iJob < len(jediJobs):
|
|
826
|
+
_logger.debug(f"reassignJobs for long activated JEDI in active table ({jediJobs[iJob:iJob + nJob]})")
|
|
827
|
+
Client.kill_jobs(jediJobs[iJob : iJob + nJob], 51, keep_unmerged=True)
|
|
828
|
+
iJob += nJob
|
|
829
|
+
|
|
830
|
+
# reassign too long starting jobs in active table
|
|
831
|
+
timeLimit = naive_utcnow() - datetime.timedelta(hours=48)
|
|
832
|
+
status, res = taskBuffer.lockJobsForReassign(
|
|
833
|
+
"ATLAS_PANDA.jobsActive4",
|
|
834
|
+
timeLimit,
|
|
835
|
+
["starting"],
|
|
836
|
+
["managed"],
|
|
837
|
+
[],
|
|
838
|
+
[],
|
|
839
|
+
[],
|
|
840
|
+
True,
|
|
841
|
+
onlyReassignable=True,
|
|
842
|
+
useStateChangeTime=True,
|
|
843
|
+
getEventService=True,
|
|
844
|
+
)
|
|
845
|
+
jediJobs = []
|
|
846
|
+
if res is not None:
|
|
847
|
+
for pandaID, lockedby, eventService, attemptNr, computingSite in res:
|
|
848
|
+
if computingSite in sitesToDisableReassign:
|
|
849
|
+
_logger.debug(f"skip reassignJobs for long starting PandaID={pandaID} since disabled at {computingSite}")
|
|
850
|
+
continue
|
|
851
|
+
if lockedby == "jedi":
|
|
852
|
+
jediJobs.append(pandaID)
|
|
853
|
+
|
|
854
|
+
_logger.debug(f"reassignJobs for long starting JEDI in active table -> #{len(jediJobs)}")
|
|
855
|
+
if len(jediJobs) != 0:
|
|
856
|
+
nJob = 100
|
|
857
|
+
iJob = 0
|
|
858
|
+
while iJob < len(jediJobs):
|
|
859
|
+
_logger.debug(f"reassignJobs for long stating JEDI in active table ({jediJobs[iJob:iJob + nJob]})")
|
|
860
|
+
Client.kill_jobs(jediJobs[iJob : iJob + nJob], 51, keep_unmerged=True)
|
|
861
|
+
iJob += nJob
|
|
862
|
+
|
|
863
|
+
# kill too long-standing analysis jobs in active table
|
|
864
|
+
timeLimit = naive_utcnow() - datetime.timedelta(days=7)
|
|
865
|
+
var_map = {}
|
|
866
|
+
var_map[":prodSourceLabel1"] = "test"
|
|
867
|
+
var_map[":prodSourceLabel2"] = "panda"
|
|
868
|
+
var_map[":prodSourceLabel3"] = "user"
|
|
869
|
+
var_map[":modificationTime"] = timeLimit
|
|
870
|
+
status, res = taskBuffer.querySQLS(
|
|
871
|
+
"SELECT PandaID FROM ATLAS_PANDA.jobsActive4 WHERE (prodSourceLabel=:prodSourceLabel1 OR prodSourceLabel=:prodSourceLabel2 OR prodSourceLabel=:prodSourceLabel3) AND modificationTime<:modificationTime ORDER BY PandaID",
|
|
872
|
+
var_map,
|
|
873
|
+
)
|
|
874
|
+
jobs = []
|
|
875
|
+
if res is not None:
|
|
876
|
+
for (id,) in res:
|
|
877
|
+
jobs.append(id)
|
|
878
|
+
# kill
|
|
879
|
+
if len(jobs):
|
|
880
|
+
Client.kill_jobs(jobs, 2)
|
|
881
|
+
_logger.debug(f"killJobs for Anal Active ({str(jobs)})")
|
|
882
|
+
|
|
883
|
+
# kill too long pending jobs
|
|
884
|
+
timeLimit = naive_utcnow() - datetime.timedelta(hours=1)
|
|
885
|
+
var_map = {}
|
|
886
|
+
var_map[":jobStatus"] = "pending"
|
|
887
|
+
var_map[":creationTime"] = timeLimit
|
|
888
|
+
status, res = taskBuffer.querySQLS(
|
|
889
|
+
"SELECT PandaID FROM ATLAS_PANDA.jobsDefined4 WHERE jobStatus=:jobStatus AND creationTime<:creationTime ",
|
|
890
|
+
var_map,
|
|
891
|
+
)
|
|
892
|
+
jobs = []
|
|
893
|
+
if res is not None:
|
|
894
|
+
for (id,) in res:
|
|
895
|
+
jobs.append(id)
|
|
896
|
+
# kill
|
|
897
|
+
if len(jobs):
|
|
898
|
+
if len(jobs):
|
|
899
|
+
nJob = 100
|
|
900
|
+
iJob = 0
|
|
901
|
+
while iJob < len(jobs):
|
|
902
|
+
_logger.debug(f"killJobs for Pending ({str(jobs[iJob:iJob + nJob])})")
|
|
903
|
+
Client.kill_jobs(jobs[iJob : iJob + nJob], 4)
|
|
904
|
+
iJob += nJob
|
|
905
|
+
|
|
906
|
+
# kick waiting ES merge jobs which were generated from fake co-jumbo
|
|
907
|
+
timeLimit = naive_utcnow() - datetime.timedelta(minutes=10)
|
|
908
|
+
var_map = {}
|
|
909
|
+
var_map[":jobStatus"] = "waiting"
|
|
910
|
+
var_map[":creationTime"] = timeLimit
|
|
911
|
+
var_map[":esMerge"] = EventServiceUtils.esMergeJobFlagNumber
|
|
912
|
+
sql = "SELECT PandaID,computingSite FROM ATLAS_PANDA.jobsDefined4 WHERE jobStatus=:jobStatus AND creationTime<:creationTime "
|
|
913
|
+
sql += "AND eventService=:esMerge ORDER BY jediTaskID "
|
|
914
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
915
|
+
jobsMap = {}
|
|
916
|
+
if res is not None:
|
|
917
|
+
for id, site in res:
|
|
918
|
+
if site not in jobsMap:
|
|
919
|
+
jobsMap[site] = []
|
|
920
|
+
jobsMap[site].append(id)
|
|
921
|
+
# kick
|
|
922
|
+
if len(jobsMap):
|
|
923
|
+
for site in jobsMap:
|
|
924
|
+
jobs = jobsMap[site]
|
|
925
|
+
nJob = 100
|
|
926
|
+
iJob = 0
|
|
927
|
+
while iJob < len(jobs):
|
|
928
|
+
_logger.debug(f"kick waiting ES merge ({str(jobs[iJob:iJob + nJob])})")
|
|
929
|
+
Client.kill_jobs(jobs[iJob : iJob + nJob], 2)
|
|
930
|
+
iJob += nJob
|
|
931
|
+
|
|
932
|
+
# kill too long waiting jobs
|
|
933
|
+
timeLimit = naive_utcnow() - datetime.timedelta(hours=1)
|
|
934
|
+
var_map = {}
|
|
935
|
+
var_map[":jobStatus"] = "waiting"
|
|
936
|
+
var_map[":creationTime"] = timeLimit
|
|
937
|
+
var_map[":coJumbo"] = EventServiceUtils.coJumboJobFlagNumber
|
|
938
|
+
sql = "SELECT PandaID FROM ATLAS_PANDA.jobsDefined4 WHERE jobStatus=:jobStatus AND creationTime<:creationTime "
|
|
939
|
+
sql += "AND (eventService IS NULL OR eventService<>:coJumbo) "
|
|
940
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
941
|
+
jobs = []
|
|
942
|
+
if res is not None:
|
|
943
|
+
for (id,) in res:
|
|
944
|
+
jobs.append(id)
|
|
945
|
+
# kill
|
|
946
|
+
if len(jobs):
|
|
947
|
+
if len(jobs):
|
|
948
|
+
nJob = 100
|
|
949
|
+
iJob = 0
|
|
950
|
+
while iJob < len(jobs):
|
|
951
|
+
_logger.debug(f"killJobs for Waiting ({str(jobs[iJob:iJob + nJob])})")
|
|
952
|
+
Client.kill_jobs(jobs[iJob : iJob + nJob], 4)
|
|
953
|
+
iJob += nJob
|
|
954
|
+
|
|
955
|
+
# kill too long running ES jobs
|
|
956
|
+
timeLimit = naive_utcnow() - datetime.timedelta(hours=24)
|
|
957
|
+
var_map = {}
|
|
958
|
+
var_map[":jobStatus1"] = "running"
|
|
959
|
+
var_map[":jobStatus2"] = "starting"
|
|
960
|
+
var_map[":timeLimit"] = timeLimit
|
|
961
|
+
var_map[":esJob"] = EventServiceUtils.esJobFlagNumber
|
|
962
|
+
var_map[":coJumbo"] = EventServiceUtils.coJumboJobFlagNumber
|
|
963
|
+
sql = "SELECT PandaID FROM ATLAS_PANDA.jobsActive4 WHERE jobStatus IN (:jobStatus1,:jobStatus2) AND stateChangeTime<:timeLimit "
|
|
964
|
+
sql += "AND eventService IN (:esJob,:coJumbo) AND currentPriority>=900 "
|
|
965
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
966
|
+
jobs = []
|
|
967
|
+
if res is not None:
|
|
968
|
+
for (id,) in res:
|
|
969
|
+
jobs.append(id)
|
|
970
|
+
# kill
|
|
971
|
+
if len(jobs):
|
|
972
|
+
nJob = 100
|
|
973
|
+
iJob = 0
|
|
974
|
+
while iJob < len(jobs):
|
|
975
|
+
_logger.debug(f"killJobs for long running ES jobs ({str(jobs[iJob:iJob + nJob])})")
|
|
976
|
+
Client.kill_jobs(
|
|
977
|
+
jobs[iJob : iJob + nJob],
|
|
978
|
+
2,
|
|
979
|
+
keep_unmerged=True,
|
|
980
|
+
job_sub_status="es_toolong",
|
|
981
|
+
)
|
|
982
|
+
iJob += nJob
|
|
983
|
+
|
|
984
|
+
# kill too long running ES merge jobs
|
|
985
|
+
timeLimit = naive_utcnow() - datetime.timedelta(hours=24)
|
|
986
|
+
var_map = {}
|
|
987
|
+
var_map[":jobStatus1"] = "running"
|
|
988
|
+
var_map[":jobStatus2"] = "starting"
|
|
989
|
+
var_map[":timeLimit"] = timeLimit
|
|
990
|
+
var_map[":esMergeJob"] = EventServiceUtils.esMergeJobFlagNumber
|
|
991
|
+
sql = "SELECT PandaID FROM ATLAS_PANDA.jobsActive4 WHERE jobStatus IN (:jobStatus1,:jobStatus2) AND stateChangeTime<:timeLimit "
|
|
992
|
+
sql += "AND eventService=:esMergeJob "
|
|
993
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
994
|
+
jobs = []
|
|
995
|
+
if res is not None:
|
|
996
|
+
for (id,) in res:
|
|
997
|
+
jobs.append(id)
|
|
998
|
+
# kill
|
|
999
|
+
if len(jobs):
|
|
1000
|
+
nJob = 100
|
|
1001
|
+
iJob = 0
|
|
1002
|
+
while iJob < len(jobs):
|
|
1003
|
+
_logger.debug(f"killJobs for long running ES merge jobs ({str(jobs[iJob:iJob + nJob])})")
|
|
1004
|
+
Client.kill_jobs(jobs[iJob : iJob + nJob], 2)
|
|
1005
|
+
iJob += nJob
|
|
1006
|
+
|
|
1007
|
+
# rebrokerage
|
|
1008
|
+
_logger.debug("Rebrokerage start")
|
|
1009
|
+
|
|
1010
|
+
# get timeout value
|
|
1011
|
+
timeoutVal = taskBuffer.getConfigValue("rebroker", "ANALY_TIMEOUT")
|
|
1012
|
+
if timeoutVal is None:
|
|
1013
|
+
timeoutVal = 12
|
|
1014
|
+
_logger.debug(f"timeout value : {timeoutVal}h")
|
|
1015
|
+
try:
|
|
1016
|
+
normalTimeLimit = naive_utcnow() - datetime.timedelta(hours=timeoutVal)
|
|
1017
|
+
sortTimeLimit = naive_utcnow() - datetime.timedelta(hours=3)
|
|
1018
|
+
sql = (
|
|
1019
|
+
"WITH p AS ("
|
|
1020
|
+
"SELECT MIN(PandaID) PandaID,jobDefinitionID,prodUserName,prodUserID,computingSite,jediTaskID,processingType,workingGroup "
|
|
1021
|
+
"FROM ATLAS_PANDA.jobsActive4 "
|
|
1022
|
+
"WHERE prodSourceLabel IN (:prodSourceLabel1,:prodSourceLabel2) "
|
|
1023
|
+
"AND jobStatus IN (:jobStatus1,:jobStatus2,:jobStatus3) "
|
|
1024
|
+
"AND jobsetID IS NOT NULL AND lockedBy=:lockedBy "
|
|
1025
|
+
"GROUP BY jobDefinitionID,prodUserName,prodUserID,computingSite,jediTaskID,processingType,workingGroup "
|
|
1026
|
+
") "
|
|
1027
|
+
"SELECT /*+ INDEX (s JOBS_STATUSLOG_PANDAID_IDX) */ "
|
|
1028
|
+
"p.jobDefinitionID,p.prodUserName,p.prodUserID,p.computingSite,s.modificationTime,p.jediTaskID,p.processingType,p.workingGroup "
|
|
1029
|
+
"FROM p, ATLAS_PANDA.jobs_statuslog s "
|
|
1030
|
+
"WHERE s.PandaID=p.PandaID AND s.jobStatus=:s_jobStatus AND s.modificationTime<:modificationTime "
|
|
1031
|
+
)
|
|
1032
|
+
var_map = {}
|
|
1033
|
+
var_map[":prodSourceLabel1"] = "user"
|
|
1034
|
+
var_map[":prodSourceLabel2"] = "panda"
|
|
1035
|
+
var_map[":modificationTime"] = sortTimeLimit
|
|
1036
|
+
var_map[":lockedBy"] = "jedi"
|
|
1037
|
+
var_map[":jobStatus1"] = "activated"
|
|
1038
|
+
var_map[":jobStatus2"] = "dummy"
|
|
1039
|
+
var_map[":jobStatus3"] = "starting"
|
|
1040
|
+
var_map[":s_jobStatus"] = "activated"
|
|
1041
|
+
# get jobs older than threshold
|
|
1042
|
+
ret, res = taskBuffer.querySQLS(sql, var_map)
|
|
1043
|
+
resList = []
|
|
1044
|
+
keyList = set()
|
|
1045
|
+
if res is not None:
|
|
1046
|
+
for tmpItem in res:
|
|
1047
|
+
(
|
|
1048
|
+
jobDefinitionID,
|
|
1049
|
+
prodUserName,
|
|
1050
|
+
prodUserID,
|
|
1051
|
+
computingSite,
|
|
1052
|
+
maxTime,
|
|
1053
|
+
jediTaskID,
|
|
1054
|
+
processingType,
|
|
1055
|
+
workingGroup,
|
|
1056
|
+
) = tmpItem
|
|
1057
|
+
tmpKey = (jediTaskID, jobDefinitionID)
|
|
1058
|
+
keyList.add(tmpKey)
|
|
1059
|
+
resList.append(tmpItem)
|
|
1060
|
+
# get stalled assigned job
|
|
1061
|
+
sqlA = "SELECT jobDefinitionID,prodUserName,prodUserID,computingSite,MAX(creationTime),jediTaskID,processingType,workingGroup "
|
|
1062
|
+
sqlA += "FROM ATLAS_PANDA.jobsDefined4 "
|
|
1063
|
+
sqlA += "WHERE prodSourceLabel IN (:prodSourceLabel1,:prodSourceLabel2) AND jobStatus IN (:jobStatus1,:jobStatus2) "
|
|
1064
|
+
sqlA += "AND creationTime<:modificationTime AND lockedBy=:lockedBy "
|
|
1065
|
+
sqlA += "GROUP BY jobDefinitionID,prodUserName,prodUserID,computingSite,jediTaskID,processingType,workingGroup "
|
|
1066
|
+
var_map = {}
|
|
1067
|
+
var_map[":prodSourceLabel1"] = "user"
|
|
1068
|
+
var_map[":prodSourceLabel2"] = "panda"
|
|
1069
|
+
var_map[":modificationTime"] = sortTimeLimit
|
|
1070
|
+
var_map[":lockedBy"] = "jedi"
|
|
1071
|
+
var_map[":jobStatus1"] = "assigned"
|
|
1072
|
+
var_map[":jobStatus2"] = "defined"
|
|
1073
|
+
retA, resA = taskBuffer.querySQLS(sqlA, var_map)
|
|
1074
|
+
if resA is not None:
|
|
1075
|
+
for tmpItem in resA:
|
|
1076
|
+
(
|
|
1077
|
+
jobDefinitionID,
|
|
1078
|
+
prodUserName,
|
|
1079
|
+
prodUserID,
|
|
1080
|
+
computingSite,
|
|
1081
|
+
maxTime,
|
|
1082
|
+
jediTaskID,
|
|
1083
|
+
processingType,
|
|
1084
|
+
workingGroup,
|
|
1085
|
+
) = tmpItem
|
|
1086
|
+
tmpKey = (jediTaskID, jobDefinitionID)
|
|
1087
|
+
if tmpKey not in keyList:
|
|
1088
|
+
keyList.add(tmpKey)
|
|
1089
|
+
resList.append(tmpItem)
|
|
1090
|
+
# sql to check recent activity
|
|
1091
|
+
sql = "SELECT PandaID,stateChangeTime,jobStatus FROM %s "
|
|
1092
|
+
sql += "WHERE prodUserName=:prodUserName AND jobDefinitionID=:jobDefinitionID "
|
|
1093
|
+
sql += "AND computingSite=:computingSite AND jediTaskID=:jediTaskID "
|
|
1094
|
+
sql += "AND jobStatus NOT IN (:jobStatus1,:jobStatus2,:jobStatus3) "
|
|
1095
|
+
sql += "AND stateChangeTime>:modificationTime "
|
|
1096
|
+
sql += "AND rownum <= 1"
|
|
1097
|
+
# sql to get associated jobs with jediTaskID
|
|
1098
|
+
sqlJJ = "SELECT PandaID FROM %s "
|
|
1099
|
+
sqlJJ += "WHERE jediTaskID=:jediTaskID AND jobStatus IN (:jobS1,:jobS2,:jobS3,:jobS4,:jobS5) "
|
|
1100
|
+
sqlJJ += "AND jobDefinitionID=:jobDefID AND computingSite=:computingSite "
|
|
1101
|
+
timeoutMap = {}
|
|
1102
|
+
if resList != []:
|
|
1103
|
+
recentRuntimeLimit = naive_utcnow() - datetime.timedelta(hours=3)
|
|
1104
|
+
# loop over all user/jobID combinations
|
|
1105
|
+
iComb = 0
|
|
1106
|
+
nComb = len(resList)
|
|
1107
|
+
_logger.debug(f"total combinations = {nComb}")
|
|
1108
|
+
for (
|
|
1109
|
+
jobDefinitionID,
|
|
1110
|
+
prodUserName,
|
|
1111
|
+
prodUserID,
|
|
1112
|
+
computingSite,
|
|
1113
|
+
maxModificationTime,
|
|
1114
|
+
jediTaskID,
|
|
1115
|
+
processingType,
|
|
1116
|
+
workingGroup,
|
|
1117
|
+
) in resList:
|
|
1118
|
+
# check if jobs with the jobID have run recently
|
|
1119
|
+
var_map = {}
|
|
1120
|
+
var_map[":jediTaskID"] = jediTaskID
|
|
1121
|
+
var_map[":computingSite"] = computingSite
|
|
1122
|
+
var_map[":prodUserName"] = prodUserName
|
|
1123
|
+
var_map[":jobDefinitionID"] = jobDefinitionID
|
|
1124
|
+
var_map[":modificationTime"] = recentRuntimeLimit
|
|
1125
|
+
var_map[":jobStatus1"] = "closed"
|
|
1126
|
+
var_map[":jobStatus2"] = "failed"
|
|
1127
|
+
var_map[":jobStatus3"] = "starting"
|
|
1128
|
+
_logger.debug(f" rebro:{iComb}/{nComb}:ID={jobDefinitionID}:{prodUserName} jediTaskID={jediTaskID} site={computingSite}")
|
|
1129
|
+
iComb += 1
|
|
1130
|
+
hasRecentJobs = False
|
|
1131
|
+
# check site
|
|
1132
|
+
if not siteMapper.checkSite(computingSite):
|
|
1133
|
+
_logger.debug(f" -> skip unknown site={computingSite}")
|
|
1134
|
+
continue
|
|
1135
|
+
# check site status
|
|
1136
|
+
tmpSiteStatus = siteMapper.getSite(computingSite).status
|
|
1137
|
+
if tmpSiteStatus not in ["offline", "test"]:
|
|
1138
|
+
if workingGroup:
|
|
1139
|
+
if workingGroup not in timeoutMap:
|
|
1140
|
+
tmp_timeoutVal = taskBuffer.getConfigValue("rebroker", f"ANALY_TIMEOUT_{workingGroup}")
|
|
1141
|
+
if tmp_timeoutVal:
|
|
1142
|
+
timeoutMap[workingGroup] = naive_utcnow() - datetime.timedelta(hours=tmp_timeoutVal)
|
|
1143
|
+
else:
|
|
1144
|
+
timeoutMap[workingGroup] = normalTimeLimit
|
|
1145
|
+
tmp_normalTimeLimit = timeoutMap[workingGroup]
|
|
1146
|
+
else:
|
|
1147
|
+
tmp_normalTimeLimit = normalTimeLimit
|
|
1148
|
+
# use normal time limit for normal site status
|
|
1149
|
+
if maxModificationTime > tmp_normalTimeLimit:
|
|
1150
|
+
_logger.debug(f" -> skip wait for normal timelimit={tmp_normalTimeLimit}<maxModTime={maxModificationTime}")
|
|
1151
|
+
continue
|
|
1152
|
+
for tableName in [
|
|
1153
|
+
"ATLAS_PANDA.jobsActive4",
|
|
1154
|
+
"ATLAS_PANDA.jobsArchived4",
|
|
1155
|
+
]:
|
|
1156
|
+
retU, resU = taskBuffer.querySQLS(sql % tableName, var_map)
|
|
1157
|
+
if resU is None:
|
|
1158
|
+
# database error
|
|
1159
|
+
raise RuntimeError("failed to check modTime")
|
|
1160
|
+
if resU != []:
|
|
1161
|
+
# found recent jobs
|
|
1162
|
+
hasRecentJobs = True
|
|
1163
|
+
_logger.debug(f" -> skip due to recent activity {resU[0][0]} to {resU[0][2]} at {resU[0][1]}")
|
|
1164
|
+
break
|
|
1165
|
+
else:
|
|
1166
|
+
_logger.debug(f" -> immediate rebro due to site status={tmpSiteStatus}")
|
|
1167
|
+
if hasRecentJobs:
|
|
1168
|
+
# skip since some jobs have run recently
|
|
1169
|
+
continue
|
|
1170
|
+
else:
|
|
1171
|
+
if jediTaskID is None:
|
|
1172
|
+
_logger.debug(" -> rebro for normal task : no action")
|
|
1173
|
+
else:
|
|
1174
|
+
_logger.debug(" -> rebro for JEDI task")
|
|
1175
|
+
killJobs = []
|
|
1176
|
+
var_map = {}
|
|
1177
|
+
var_map[":jediTaskID"] = jediTaskID
|
|
1178
|
+
var_map[":jobDefID"] = jobDefinitionID
|
|
1179
|
+
var_map[":computingSite"] = computingSite
|
|
1180
|
+
var_map[":jobS1"] = "defined"
|
|
1181
|
+
var_map[":jobS2"] = "assigned"
|
|
1182
|
+
var_map[":jobS3"] = "activated"
|
|
1183
|
+
var_map[":jobS4"] = "dummy"
|
|
1184
|
+
var_map[":jobS5"] = "starting"
|
|
1185
|
+
for tableName in [
|
|
1186
|
+
"ATLAS_PANDA.jobsDefined4",
|
|
1187
|
+
"ATLAS_PANDA.jobsActive4",
|
|
1188
|
+
]:
|
|
1189
|
+
retJJ, resJJ = taskBuffer.querySQLS(sqlJJ % tableName, var_map)
|
|
1190
|
+
for (tmpPandaID,) in resJJ:
|
|
1191
|
+
killJobs.append(tmpPandaID)
|
|
1192
|
+
# reverse sort to kill buildJob in the end
|
|
1193
|
+
killJobs.sort()
|
|
1194
|
+
killJobs.reverse()
|
|
1195
|
+
# kill to reassign
|
|
1196
|
+
taskBuffer.killJobs(killJobs, "JEDI", "51", True)
|
|
1197
|
+
except Exception as e:
|
|
1198
|
+
_logger.error(f"rebrokerage failed with {str(e)} : {traceback.format_exc()}")
|
|
1199
|
+
|
|
1200
|
+
# kill too long running jobs
|
|
1201
|
+
timeLimit = naive_utcnow() - datetime.timedelta(days=21)
|
|
1202
|
+
status, res = taskBuffer.querySQLS(
|
|
1203
|
+
"SELECT PandaID FROM ATLAS_PANDA.jobsActive4 WHERE creationTime<:creationTime",
|
|
1204
|
+
{":creationTime": timeLimit},
|
|
1205
|
+
)
|
|
1206
|
+
jobs = []
|
|
1207
|
+
if res is not None:
|
|
1208
|
+
for (id,) in res:
|
|
1209
|
+
jobs.append(id)
|
|
1210
|
+
# kill
|
|
1211
|
+
if len(jobs):
|
|
1212
|
+
nJob = 100
|
|
1213
|
+
iJob = 0
|
|
1214
|
+
while iJob < len(jobs):
|
|
1215
|
+
# set tobekill
|
|
1216
|
+
_logger.debug(f"killJobs for Running ({jobs[iJob:iJob + nJob]})")
|
|
1217
|
+
Client.kill_jobs(jobs[iJob : iJob + nJob], 2)
|
|
1218
|
+
# run watcher
|
|
1219
|
+
for id in jobs[iJob : iJob + nJob]:
|
|
1220
|
+
thr = Watcher(
|
|
1221
|
+
taskBuffer,
|
|
1222
|
+
id,
|
|
1223
|
+
single=True,
|
|
1224
|
+
sitemapper=siteMapper,
|
|
1225
|
+
sleepTime=60 * 24 * 21,
|
|
1226
|
+
)
|
|
1227
|
+
thr.start()
|
|
1228
|
+
thr.join()
|
|
1229
|
+
time.sleep(1)
|
|
1230
|
+
iJob += nJob
|
|
1231
|
+
time.sleep(10)
|
|
1232
|
+
|
|
1233
|
+
# kill too long throttled jobs
|
|
1234
|
+
timeLimit = naive_utcnow() - datetime.timedelta(days=7)
|
|
1235
|
+
var_map = {}
|
|
1236
|
+
var_map[":jobStatus"] = "throttled"
|
|
1237
|
+
var_map[":creationTime"] = timeLimit
|
|
1238
|
+
status, res = taskBuffer.querySQLS(
|
|
1239
|
+
"SELECT PandaID FROM ATLAS_PANDA.jobsActive4 WHERE jobStatus=:jobStatus AND creationTime<:creationTime ",
|
|
1240
|
+
var_map,
|
|
1241
|
+
)
|
|
1242
|
+
jobs = []
|
|
1243
|
+
if res is not None:
|
|
1244
|
+
for (id,) in res:
|
|
1245
|
+
jobs.append(id)
|
|
1246
|
+
# kill
|
|
1247
|
+
if len(jobs):
|
|
1248
|
+
Client.kill_jobs(jobs, 2)
|
|
1249
|
+
_logger.debug(f"killJobs for throttled ({str(jobs)})")
|
|
1250
|
+
|
|
1251
|
+
# check if merge job is valid
|
|
1252
|
+
_logger.debug("kill invalid pmerge")
|
|
1253
|
+
var_map = {}
|
|
1254
|
+
var_map[":processingType"] = "pmerge"
|
|
1255
|
+
var_map[":timeLimit"] = naive_utcnow() - datetime.timedelta(minutes=30)
|
|
1256
|
+
sql = "SELECT PandaID,jediTaskID FROM ATLAS_PANDA.jobsDefined4 WHERE processingType=:processingType AND modificationTime<:timeLimit "
|
|
1257
|
+
sql += "UNION "
|
|
1258
|
+
sql += "SELECT PandaID,jediTaskID FROM ATLAS_PANDA.jobsActive4 WHERE processingType=:processingType AND modificationTime<:timeLimit "
|
|
1259
|
+
status, res = taskBuffer.querySQLS(sql, var_map)
|
|
1260
|
+
nPmerge = 0
|
|
1261
|
+
badPmerge = 0
|
|
1262
|
+
_logger.debug(f"check {len(res)} pmerge")
|
|
1263
|
+
for pandaID, jediTaskID in res:
|
|
1264
|
+
nPmerge += 1
|
|
1265
|
+
isValid, tmpMsg = taskBuffer.isValidMergeJob(pandaID, jediTaskID)
|
|
1266
|
+
if isValid is False:
|
|
1267
|
+
_logger.debug(f"kill pmerge {pandaID} since {tmpMsg} gone")
|
|
1268
|
+
taskBuffer.killJobs(
|
|
1269
|
+
[pandaID],
|
|
1270
|
+
f"killed since pre-merge job {tmpMsg} gone",
|
|
1271
|
+
"52",
|
|
1272
|
+
True,
|
|
1273
|
+
)
|
|
1274
|
+
badPmerge += 1
|
|
1275
|
+
_logger.debug(f"killed invalid pmerge {badPmerge}/{nPmerge}")
|
|
1276
|
+
|
|
1277
|
+
# cleanup of jumbo jobs
|
|
1278
|
+
_logger.debug("jumbo job cleanup")
|
|
1279
|
+
res = taskBuffer.cleanupJumboJobs()
|
|
1280
|
+
_logger.debug(res)
|
|
1281
|
+
|
|
1282
|
+
_memoryCheck("delete XML")
|
|
1283
|
+
|
|
1284
|
+
# delete old files in DA cache
|
|
1285
|
+
timeLimit = naive_utcnow() - datetime.timedelta(days=7)
|
|
1286
|
+
files = os.listdir(panda_config.cache_dir)
|
|
1287
|
+
for file in files:
|
|
1288
|
+
# skip special test file
|
|
1289
|
+
if file == "sources.72c48dc5-f055-43e5-a86e-4ae9f8ea3497.tar.gz":
|
|
1290
|
+
continue
|
|
1291
|
+
if file == "sources.090f3f51-fc81-4e80-9749-a5e4b2bd58de.tar.gz":
|
|
1292
|
+
continue
|
|
1293
|
+
try:
|
|
1294
|
+
# get timestamp
|
|
1295
|
+
timestamp = datetime.datetime.fromtimestamp(os.stat(f"{panda_config.cache_dir}/{file}").st_mtime)
|
|
1296
|
+
# delete
|
|
1297
|
+
if timestamp < timeLimit:
|
|
1298
|
+
_logger.debug(f"delete {file} ")
|
|
1299
|
+
os.remove(f"{panda_config.cache_dir}/{file}")
|
|
1300
|
+
except Exception:
|
|
1301
|
+
pass
|
|
1302
|
+
|
|
1303
|
+
_memoryCheck("delete core")
|
|
1304
|
+
|
|
1305
|
+
# delete core
|
|
1306
|
+
dirName = f"{panda_config.logdir}/.."
|
|
1307
|
+
for file in os.listdir(dirName):
|
|
1308
|
+
if file.startswith("core."):
|
|
1309
|
+
_logger.debug(f"delete {file} ")
|
|
1310
|
+
try:
|
|
1311
|
+
os.remove(f"{dirName}/{file}")
|
|
1312
|
+
except Exception:
|
|
1313
|
+
pass
|
|
1314
|
+
|
|
1315
|
+
# sandbox
|
|
1316
|
+
_logger.debug("Touch sandbox")
|
|
1317
|
+
timeLimit = naive_utcnow() - datetime.timedelta(days=1)
|
|
1318
|
+
sqlC = (
|
|
1319
|
+
"SELECT hostName,fileName,creationTime,userName FROM ATLAS_PANDAMETA.userCacheUsage "
|
|
1320
|
+
"WHERE creationTime>:timeLimit AND creationTime>modificationTime "
|
|
1321
|
+
"AND (fileName like 'sources%' OR fileName like 'jobO%') "
|
|
1322
|
+
)
|
|
1323
|
+
sqlU = "UPDATE ATLAS_PANDAMETA.userCacheUsage SET modificationTime=CURRENT_DATE " "WHERE userName=:userName AND fileName=:fileName "
|
|
1324
|
+
status, res = taskBuffer.querySQLS(sqlC, {":timeLimit": timeLimit})
|
|
1325
|
+
if res is None:
|
|
1326
|
+
_logger.error("failed to get files")
|
|
1327
|
+
elif len(res) > 0:
|
|
1328
|
+
_logger.debug(f"{len(res)} files to touch")
|
|
1329
|
+
for hostName, fileName, creationTime, userName in res:
|
|
1330
|
+
base_url = f"https://{hostName}:{panda_config.pserverport}"
|
|
1331
|
+
_logger.debug(f"touch {fileName} on {hostName} created at {creationTime}")
|
|
1332
|
+
s, o = Client.touch_file(base_url, fileName)
|
|
1333
|
+
_logger.debug(o)
|
|
1334
|
+
if o == "True":
|
|
1335
|
+
var_map = dict()
|
|
1336
|
+
var_map[":userName"] = userName
|
|
1337
|
+
var_map[":fileName"] = fileName
|
|
1338
|
+
taskBuffer.querySQLS(sqlU, var_map)
|
|
1339
|
+
|
|
1340
|
+
_logger.debug("Check sandbox")
|
|
1341
|
+
timeLimit = naive_utcnow() - datetime.timedelta(days=1)
|
|
1342
|
+
expireLimit = naive_utcnow() - datetime.timedelta(days=30)
|
|
1343
|
+
sqlD = "DELETE FROM ATLAS_PANDAMETA.userCacheUsage WHERE userName=:userName AND fileName=:fileName "
|
|
1344
|
+
nRange = 100
|
|
1345
|
+
for i in range(nRange):
|
|
1346
|
+
_logger.debug(f"{nRange}/{i} {len(res)} files to check")
|
|
1347
|
+
res = taskBuffer.getLockSandboxFiles(timeLimit, 1000)
|
|
1348
|
+
if res is None:
|
|
1349
|
+
_logger.error("failed to get files")
|
|
1350
|
+
break
|
|
1351
|
+
elif len(res) == 0:
|
|
1352
|
+
break
|
|
1353
|
+
for userName, hostName, fileName, creationTime, modificationTime in res:
|
|
1354
|
+
url = f"https://{hostName}:{panda_config.pserverport}/cache/{fileName}"
|
|
1355
|
+
_logger.debug(f"checking {url} created at {creationTime}")
|
|
1356
|
+
toDelete = False
|
|
1357
|
+
try:
|
|
1358
|
+
x = requests.head(url, verify=False)
|
|
1359
|
+
_logger.debug(f"code {x.status_code}")
|
|
1360
|
+
if x.status_code == 404:
|
|
1361
|
+
_logger.debug("delete")
|
|
1362
|
+
toDelete = True
|
|
1363
|
+
except Exception as e:
|
|
1364
|
+
_logger.debug(f"failed with {str(e)}")
|
|
1365
|
+
if creationTime < expireLimit:
|
|
1366
|
+
toDelete = True
|
|
1367
|
+
_logger.debug(f"delete due to creationTime={creationTime}")
|
|
1368
|
+
# update or delete
|
|
1369
|
+
var_map = dict()
|
|
1370
|
+
var_map[":userName"] = userName
|
|
1371
|
+
var_map[":fileName"] = fileName
|
|
1372
|
+
if toDelete:
|
|
1373
|
+
taskBuffer.querySQLS(sqlD, var_map)
|
|
1374
|
+
else:
|
|
1375
|
+
_logger.debug("keep")
|
|
1376
|
+
|
|
1377
|
+
_memoryCheck("end")
|
|
1378
|
+
|
|
1379
|
+
# stop taskBuffer if created inside this script
|
|
1380
|
+
taskBuffer.cleanup(requester=requester_id)
|
|
1381
|
+
|
|
1382
|
+
_logger.debug("===================== end =====================")
|
|
1383
|
+
|
|
1384
|
+
|
|
1385
|
+
# run
|
|
1386
|
+
if __name__ == "__main__":
|
|
1387
|
+
main(argv=sys.argv)
|