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,308 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
|
|
3
|
+
from pandacommon.pandalogger.PandaLogger import PandaLogger
|
|
4
|
+
|
|
5
|
+
from pandajedi.jedicore import Interaction
|
|
6
|
+
from pandajedi.jedicore.MsgWrapper import MsgWrapper
|
|
7
|
+
from pandaserver.srvcore import CoreUtils
|
|
8
|
+
from pandaserver.taskbuffer.InputChunk import InputChunk
|
|
9
|
+
|
|
10
|
+
logger = PandaLogger().getLogger(__name__.split(".")[-1])
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# class to split job
|
|
14
|
+
class JobSplitter:
|
|
15
|
+
# constructor
|
|
16
|
+
def __init__(self):
|
|
17
|
+
self.sizeGradientsPerInSizeForMerge = 1.2
|
|
18
|
+
self.interceptsMerginForMerge = 500 * 1024 * 1024
|
|
19
|
+
|
|
20
|
+
# split
|
|
21
|
+
def doSplit(self, taskSpec, inputChunk, siteMapper, allow_chunk_size_limit=False):
|
|
22
|
+
# return for failure
|
|
23
|
+
retFatal = self.SC_FATAL, []
|
|
24
|
+
retTmpError = self.SC_FAILED, []
|
|
25
|
+
# make logger
|
|
26
|
+
tmpLog = MsgWrapper(logger, f"< jediTaskID={taskSpec.jediTaskID} datasetID={inputChunk.masterIndexName} >")
|
|
27
|
+
tmpLog.debug(f"--- start chunk_size_limit={allow_chunk_size_limit}")
|
|
28
|
+
if not inputChunk.isMerging:
|
|
29
|
+
# set maxNumFiles using taskSpec if specified
|
|
30
|
+
maxNumFiles = taskSpec.getMaxNumFilesPerJob()
|
|
31
|
+
# set fsize gradients using taskSpec
|
|
32
|
+
sizeGradients = taskSpec.getOutDiskSize()
|
|
33
|
+
# set fsize intercepts using taskSpec
|
|
34
|
+
sizeIntercepts = taskSpec.getWorkDiskSize()
|
|
35
|
+
# walltime
|
|
36
|
+
if not taskSpec.useHS06():
|
|
37
|
+
walltimeGradient = taskSpec.walltime
|
|
38
|
+
else:
|
|
39
|
+
walltimeGradient = taskSpec.getCpuTime()
|
|
40
|
+
# number of events per job if defined
|
|
41
|
+
nEventsPerJob = taskSpec.getNumEventsPerJob()
|
|
42
|
+
# number of files per job if defined
|
|
43
|
+
nFilesPerJob = taskSpec.getNumFilesPerJob()
|
|
44
|
+
if nFilesPerJob is None and nEventsPerJob is None and inputChunk.useScout() and not taskSpec.useLoadXML() and not taskSpec.respectSplitRule():
|
|
45
|
+
nFilesPerJob = 1
|
|
46
|
+
# grouping with boundaryID
|
|
47
|
+
useBoundary = taskSpec.useGroupWithBoundaryID()
|
|
48
|
+
# fsize intercepts per input size
|
|
49
|
+
sizeGradientsPerInSize = None
|
|
50
|
+
# set max primay output size to avoid producing huge unmerged files
|
|
51
|
+
maxOutSize = 10 * 1024 * 1024 * 1024
|
|
52
|
+
# max size per job
|
|
53
|
+
maxSizePerJob = taskSpec.getMaxSizePerJob()
|
|
54
|
+
if maxSizePerJob is not None:
|
|
55
|
+
maxSizePerJob += InputChunk.defaultOutputSize
|
|
56
|
+
# multiplicity of jobs
|
|
57
|
+
if taskSpec.useJobCloning():
|
|
58
|
+
multiplicity = 1
|
|
59
|
+
else:
|
|
60
|
+
multiplicity = taskSpec.getNumEventServiceConsumer()
|
|
61
|
+
# split with fields
|
|
62
|
+
if taskSpec.getFieldNumToLFN() is not None and taskSpec.useFileAsSourceLFN():
|
|
63
|
+
splitByFields = taskSpec.getFieldNumToLFN()
|
|
64
|
+
else:
|
|
65
|
+
splitByFields = None
|
|
66
|
+
else:
|
|
67
|
+
# set parameters for merging
|
|
68
|
+
maxNumFiles = taskSpec.getMaxNumFilesPerMergeJob()
|
|
69
|
+
sizeGradients = 0
|
|
70
|
+
walltimeGradient = 0
|
|
71
|
+
nFilesPerJob = taskSpec.getNumFilesPerMergeJob()
|
|
72
|
+
nEventsPerJob = taskSpec.getNumEventsPerMergeJob()
|
|
73
|
+
maxSizePerJob = None
|
|
74
|
+
useBoundary = {"inSplit": 3}
|
|
75
|
+
multiplicity = None
|
|
76
|
+
# gradients per input size is 1 + margin
|
|
77
|
+
sizeGradientsPerInSize = self.sizeGradientsPerInSizeForMerge
|
|
78
|
+
# intercepts for libDS
|
|
79
|
+
sizeIntercepts = taskSpec.getWorkDiskSize()
|
|
80
|
+
# mergein of 500MB
|
|
81
|
+
interceptsMergin = self.interceptsMerginForMerge
|
|
82
|
+
if sizeIntercepts < interceptsMergin:
|
|
83
|
+
sizeIntercepts = interceptsMergin
|
|
84
|
+
maxOutSize = taskSpec.getMaxSizePerMergeJob()
|
|
85
|
+
if maxOutSize is None:
|
|
86
|
+
# max output size is 5GB for merging by default
|
|
87
|
+
maxOutSize = 5 * 1024 * 1024 * 1024
|
|
88
|
+
# split with fields
|
|
89
|
+
if taskSpec.getFieldNumToLFN() is not None and taskSpec.useFileAsSourceLFN():
|
|
90
|
+
splitByFields = list(range(4 + 1, 4 + 1 + len(taskSpec.getFieldNumToLFN())))
|
|
91
|
+
else:
|
|
92
|
+
splitByFields = None
|
|
93
|
+
# LB
|
|
94
|
+
respectLB = taskSpec.respectLumiblock()
|
|
95
|
+
# no split for on-site merging
|
|
96
|
+
if taskSpec.on_site_merging():
|
|
97
|
+
no_split = True
|
|
98
|
+
else:
|
|
99
|
+
no_split = False
|
|
100
|
+
# dump
|
|
101
|
+
tmpLog.debug(f"maxNumFiles={maxNumFiles} sizeGradients={sizeGradients} sizeIntercepts={sizeIntercepts} useBoundary={useBoundary}")
|
|
102
|
+
tmpLog.debug(f"walltimeGradient={walltimeGradient} nFilesPerJob={nFilesPerJob} nEventsPerJob={nEventsPerJob}")
|
|
103
|
+
tmpLog.debug(f"useScout={inputChunk.useScout()} isMerging={inputChunk.isMerging}")
|
|
104
|
+
tmpLog.debug(f"sizeGradientsPerInSize={sizeGradientsPerInSize} maxOutSize={maxOutSize} respectLB={respectLB}")
|
|
105
|
+
tmpLog.debug(
|
|
106
|
+
f"multiplicity={multiplicity} splitByFields={str(splitByFields)} "
|
|
107
|
+
f"nFiles={inputChunk.getNumFilesInMaster()} no_split={no_split} "
|
|
108
|
+
f"maxEventsPerJob={taskSpec.get_max_events_per_job()}"
|
|
109
|
+
)
|
|
110
|
+
tmpLog.debug("--- main loop")
|
|
111
|
+
# split
|
|
112
|
+
returnList = []
|
|
113
|
+
subChunks = []
|
|
114
|
+
iSubChunks = 0
|
|
115
|
+
if inputChunk.useScout() and not inputChunk.isMerging:
|
|
116
|
+
default_nSubChunks = 2
|
|
117
|
+
elif taskSpec.is_hpo_workflow():
|
|
118
|
+
default_nSubChunks = 2
|
|
119
|
+
else:
|
|
120
|
+
default_nSubChunks = 25
|
|
121
|
+
subChunk = None
|
|
122
|
+
nSubChunks = default_nSubChunks
|
|
123
|
+
strict_chunkSize = False
|
|
124
|
+
tmp_ng_list = []
|
|
125
|
+
change_site_for_dist_dataset = False
|
|
126
|
+
while True:
|
|
127
|
+
# change site
|
|
128
|
+
if iSubChunks % nSubChunks == 0 or subChunk == [] or change_site_for_dist_dataset:
|
|
129
|
+
change_site_for_dist_dataset = False
|
|
130
|
+
# append to return map
|
|
131
|
+
if subChunks != []:
|
|
132
|
+
# get site names for parallel execution
|
|
133
|
+
if taskSpec.getNumSitesPerJob() > 1 and not inputChunk.isMerging and inputChunk.useJumbo != "fake":
|
|
134
|
+
siteName = inputChunk.getParallelSites(taskSpec.getNumSitesPerJob(), nSubChunks, [siteName])
|
|
135
|
+
returnList.append(
|
|
136
|
+
{
|
|
137
|
+
"siteName": siteName,
|
|
138
|
+
"subChunks": subChunks,
|
|
139
|
+
"siteCandidate": siteCandidate,
|
|
140
|
+
}
|
|
141
|
+
)
|
|
142
|
+
try:
|
|
143
|
+
gshare = taskSpec.gshare.replace(" ", "_")
|
|
144
|
+
except Exception:
|
|
145
|
+
gshare = None
|
|
146
|
+
tmpLog.info(f"split to nJobs={len(subChunks)} at site={siteName} gshare={gshare}")
|
|
147
|
+
# checkpoint
|
|
148
|
+
inputChunk.checkpoint_file_usage()
|
|
149
|
+
# reset
|
|
150
|
+
subChunks = []
|
|
151
|
+
# skip PQs with chunk size limit
|
|
152
|
+
ngList = copy.copy(tmp_ng_list)
|
|
153
|
+
if not allow_chunk_size_limit:
|
|
154
|
+
for siteName in inputChunk.get_candidate_names():
|
|
155
|
+
siteSpec = siteMapper.getSite(siteName)
|
|
156
|
+
if siteSpec.get_job_chunk_size() is not None:
|
|
157
|
+
ngList.append(siteName)
|
|
158
|
+
# new candidate
|
|
159
|
+
siteCandidate, getCandidateMsg = inputChunk.getOneSiteCandidate(nSubChunks, ngSites=ngList, get_msg=True)
|
|
160
|
+
if siteCandidate is None:
|
|
161
|
+
tmpLog.debug(f"no candidate: {getCandidateMsg}")
|
|
162
|
+
break
|
|
163
|
+
tmp_ng_list = []
|
|
164
|
+
siteName = siteCandidate.siteName
|
|
165
|
+
siteSpec = siteMapper.getSite(siteName)
|
|
166
|
+
# set chunk size
|
|
167
|
+
nSubChunks = siteSpec.get_job_chunk_size()
|
|
168
|
+
if nSubChunks is None:
|
|
169
|
+
nSubChunks = default_nSubChunks
|
|
170
|
+
strict_chunkSize = False
|
|
171
|
+
else:
|
|
172
|
+
strict_chunkSize = True
|
|
173
|
+
# directIO
|
|
174
|
+
if not CoreUtils.use_direct_io_for_job(taskSpec, siteSpec, inputChunk):
|
|
175
|
+
useDirectIO = False
|
|
176
|
+
else:
|
|
177
|
+
useDirectIO = True
|
|
178
|
+
# get maxSize if it is set in taskSpec
|
|
179
|
+
maxSize = maxSizePerJob
|
|
180
|
+
if maxSize is None:
|
|
181
|
+
# use maxwdir as the default maxSize
|
|
182
|
+
if not useDirectIO:
|
|
183
|
+
maxSize = siteCandidate.get_overridden_attribute("maxwdir")
|
|
184
|
+
if maxSize is None:
|
|
185
|
+
maxSize = siteSpec.maxwdir
|
|
186
|
+
if maxSize:
|
|
187
|
+
maxSize *= 1024 * 1024
|
|
188
|
+
elif nEventsPerJob is not None or nFilesPerJob is not None:
|
|
189
|
+
maxSize = None
|
|
190
|
+
else:
|
|
191
|
+
maxSize = siteCandidate.get_overridden_attribute("maxwdir")
|
|
192
|
+
if maxSize is None:
|
|
193
|
+
maxSize = siteSpec.maxwdir
|
|
194
|
+
if inputChunk.useScout():
|
|
195
|
+
maxSize = max(inputChunk.maxInputSizeScouts, maxSize) * 1024 * 1024
|
|
196
|
+
else:
|
|
197
|
+
maxSize = max(inputChunk.maxInputSizeAvalanche, maxSize) * 1024 * 1024
|
|
198
|
+
else:
|
|
199
|
+
# add offset
|
|
200
|
+
maxSize += sizeIntercepts
|
|
201
|
+
# max disk size
|
|
202
|
+
maxDiskSize = siteCandidate.get_overridden_attribute("maxwdir")
|
|
203
|
+
if maxDiskSize is None:
|
|
204
|
+
maxDiskSize = siteSpec.maxwdir
|
|
205
|
+
if maxDiskSize:
|
|
206
|
+
maxDiskSize *= 1024 * 1024
|
|
207
|
+
# max walltime
|
|
208
|
+
maxWalltime = None
|
|
209
|
+
if not inputChunk.isMerging:
|
|
210
|
+
maxWalltime = taskSpec.getMaxWalltime()
|
|
211
|
+
if maxWalltime is None:
|
|
212
|
+
maxWalltime = siteSpec.maxtime
|
|
213
|
+
# core count
|
|
214
|
+
if siteSpec.coreCount:
|
|
215
|
+
coreCount = siteSpec.coreCount
|
|
216
|
+
else:
|
|
217
|
+
coreCount = 1
|
|
218
|
+
# core power
|
|
219
|
+
corePower = siteSpec.corepower
|
|
220
|
+
if taskSpec.dynamicNumEvents() and siteSpec.mintime:
|
|
221
|
+
dynNumEvents = True
|
|
222
|
+
else:
|
|
223
|
+
dynNumEvents = False
|
|
224
|
+
tmpLog.debug(f"chosen {siteName} : {getCandidateMsg} : nQueue={siteCandidate.nQueuedJobs} nRunCap={siteCandidate.nRunningJobsCap}")
|
|
225
|
+
tmpLog.debug(f"new weight {siteCandidate.weight}")
|
|
226
|
+
tmpLog.debug(
|
|
227
|
+
f"maxSize={maxSize} maxWalltime={maxWalltime} coreCount={coreCount} corePower={corePower} maxDisk={maxDiskSize} dynNumEvents={dynNumEvents}"
|
|
228
|
+
)
|
|
229
|
+
tmpLog.debug(f"useDirectIO={useDirectIO} label={taskSpec.prodSourceLabel}")
|
|
230
|
+
# get sub chunk
|
|
231
|
+
subChunk, _ = inputChunk.getSubChunk(
|
|
232
|
+
siteName,
|
|
233
|
+
maxSize=maxSize,
|
|
234
|
+
maxNumFiles=maxNumFiles,
|
|
235
|
+
sizeGradients=sizeGradients,
|
|
236
|
+
sizeIntercepts=sizeIntercepts,
|
|
237
|
+
nFilesPerJob=nFilesPerJob,
|
|
238
|
+
walltimeGradient=walltimeGradient,
|
|
239
|
+
maxWalltime=maxWalltime,
|
|
240
|
+
nEventsPerJob=nEventsPerJob,
|
|
241
|
+
useBoundary=useBoundary,
|
|
242
|
+
sizeGradientsPerInSize=sizeGradientsPerInSize,
|
|
243
|
+
maxOutSize=maxOutSize,
|
|
244
|
+
coreCount=coreCount,
|
|
245
|
+
respectLB=respectLB,
|
|
246
|
+
corePower=corePower,
|
|
247
|
+
dynNumEvents=dynNumEvents,
|
|
248
|
+
multiplicity=multiplicity,
|
|
249
|
+
splitByFields=splitByFields,
|
|
250
|
+
tmpLog=tmpLog,
|
|
251
|
+
useDirectIO=useDirectIO,
|
|
252
|
+
maxDiskSize=maxDiskSize,
|
|
253
|
+
enableLog=True,
|
|
254
|
+
no_split=no_split,
|
|
255
|
+
min_walltime=siteSpec.mintime,
|
|
256
|
+
max_events=taskSpec.get_max_events_per_job(),
|
|
257
|
+
)
|
|
258
|
+
if subChunk is None:
|
|
259
|
+
break
|
|
260
|
+
if subChunk != []:
|
|
261
|
+
# append
|
|
262
|
+
subChunks.append(subChunk)
|
|
263
|
+
# intermediate checkpoint
|
|
264
|
+
inputChunk.checkpoint_file_usage(intermediate=True)
|
|
265
|
+
# check if the last file in master dist dataset is locally available
|
|
266
|
+
for tmp_dataset, tmp_files in subChunk:
|
|
267
|
+
if tmp_dataset.isMaster():
|
|
268
|
+
if tmp_dataset.isDistributed() and not siteCandidate.isAvailableFile(tmp_files[-1]) and siteCandidate.isAvailableFile(tmp_files[0]):
|
|
269
|
+
change_site_for_dist_dataset = True
|
|
270
|
+
tmpLog.debug(
|
|
271
|
+
f"change site since the last file in distributed sub-dataset was unavailable at {siteName} while the first file was available"
|
|
272
|
+
)
|
|
273
|
+
break
|
|
274
|
+
else:
|
|
275
|
+
tmp_ng_list.append(siteName)
|
|
276
|
+
inputChunk.rollback_file_usage(intermediate=True)
|
|
277
|
+
tmpLog.debug("rollback to intermediate file usage")
|
|
278
|
+
iSubChunks += 1
|
|
279
|
+
# append to return map if remain
|
|
280
|
+
isSkipped = False
|
|
281
|
+
if subChunks != []:
|
|
282
|
+
# skip if chunk size is not enough
|
|
283
|
+
if allow_chunk_size_limit and strict_chunkSize and len(subChunks) < nSubChunks:
|
|
284
|
+
tmpLog.debug(f"skip splitting since chunk size {len(subChunks)} is less than chunk size limit {nSubChunks} at {siteName}")
|
|
285
|
+
inputChunk.rollback_file_usage()
|
|
286
|
+
isSkipped = True
|
|
287
|
+
else:
|
|
288
|
+
# get site names for parallel execution
|
|
289
|
+
if taskSpec.getNumSitesPerJob() > 1 and not inputChunk.isMerging:
|
|
290
|
+
siteName = inputChunk.getParallelSites(taskSpec.getNumSitesPerJob(), nSubChunks, [siteName])
|
|
291
|
+
returnList.append(
|
|
292
|
+
{
|
|
293
|
+
"siteName": siteName,
|
|
294
|
+
"subChunks": subChunks,
|
|
295
|
+
"siteCandidate": siteCandidate,
|
|
296
|
+
}
|
|
297
|
+
)
|
|
298
|
+
try:
|
|
299
|
+
gshare = taskSpec.gshare.replace(" ", "_")
|
|
300
|
+
except Exception:
|
|
301
|
+
gshare = None
|
|
302
|
+
tmpLog.info(f"split to nJobs={len(subChunks)} at site={siteName} gshare={gshare}")
|
|
303
|
+
# return
|
|
304
|
+
tmpLog.debug("--- done")
|
|
305
|
+
return self.SC_SUCCEEDED, returnList, isSkipped
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
Interaction.installSC(JobSplitter)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from pandacommon.pandalogger.PandaLogger import PandaLogger
|
|
2
|
+
|
|
3
|
+
from pandajedi.jediconfig import jedi_config
|
|
4
|
+
from pandajedi.jedicore.FactoryBase import FactoryBase
|
|
5
|
+
|
|
6
|
+
logger = PandaLogger().getLogger(__name__.split(".")[-1])
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# factory class for throttling
|
|
10
|
+
class JobThrottler(FactoryBase):
|
|
11
|
+
# constructor
|
|
12
|
+
def __init__(self, vo, sourceLabel):
|
|
13
|
+
FactoryBase.__init__(self, vo, sourceLabel, logger, jedi_config.jobthrottle.modConfig)
|
|
14
|
+
|
|
15
|
+
# main
|
|
16
|
+
def toBeThrottled(self, vo, sourceLabel, cloudName, workQueue, resourceType):
|
|
17
|
+
impl = self.getImpl(vo, sourceLabel)
|
|
18
|
+
retVal = impl.toBeThrottled(vo, sourceLabel, cloudName, workQueue, resourceType)
|
|
19
|
+
# retrieve min priority and max number of jobs from concrete class
|
|
20
|
+
self.minPriority = impl.minPriority
|
|
21
|
+
self.maxNumJobs = impl.maxNumJobs
|
|
22
|
+
self.lackOfJobs = impl.underNqLimit
|
|
23
|
+
return retVal
|
|
24
|
+
|
|
25
|
+
# check throttle level
|
|
26
|
+
def mergeThrottled(self, vo, sourceLabel, thrLevel):
|
|
27
|
+
impl = self.getImpl(vo, sourceLabel)
|
|
28
|
+
return impl.mergeThrottled(thrLevel)
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import os
|
|
3
|
+
import socket
|
|
4
|
+
import sys
|
|
5
|
+
import time
|
|
6
|
+
|
|
7
|
+
from pandacommon.pandalogger.PandaLogger import PandaLogger
|
|
8
|
+
from pandacommon.pandautils.PandaUtils import naive_utcnow
|
|
9
|
+
|
|
10
|
+
from pandajedi.jediconfig import jedi_config
|
|
11
|
+
from pandajedi.jedicore import Interaction
|
|
12
|
+
from pandajedi.jedicore.FactoryBase import FactoryBase
|
|
13
|
+
from pandajedi.jedicore.MsgWrapper import MsgWrapper
|
|
14
|
+
from pandajedi.jedicore.ThreadUtils import ListWithLock, ThreadPool, WorkerThread
|
|
15
|
+
|
|
16
|
+
from .JediKnight import JediKnight
|
|
17
|
+
|
|
18
|
+
logger = PandaLogger().getLogger(__name__.split(".")[-1])
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# worker class to do post-processing
|
|
22
|
+
class PostProcessor(JediKnight, FactoryBase):
|
|
23
|
+
# constructor
|
|
24
|
+
def __init__(self, commuChannel, taskBufferIF, ddmIF, vos, prodSourceLabels):
|
|
25
|
+
self.vos = self.parseInit(vos)
|
|
26
|
+
self.prodSourceLabels = self.parseInit(prodSourceLabels)
|
|
27
|
+
self.pid = f"{socket.getfqdn().split('.')[0]}-{os.getpid()}-post"
|
|
28
|
+
JediKnight.__init__(self, commuChannel, taskBufferIF, ddmIF, logger)
|
|
29
|
+
FactoryBase.__init__(self, self.vos, self.prodSourceLabels, logger, jedi_config.postprocessor.modConfig)
|
|
30
|
+
|
|
31
|
+
# main
|
|
32
|
+
def start(self):
|
|
33
|
+
# start base classes
|
|
34
|
+
JediKnight.start(self)
|
|
35
|
+
FactoryBase.initializeMods(self, self.taskBufferIF, self.ddmIF)
|
|
36
|
+
# go into main loop
|
|
37
|
+
while True:
|
|
38
|
+
startTime = naive_utcnow()
|
|
39
|
+
try:
|
|
40
|
+
# get logger
|
|
41
|
+
tmpLog = MsgWrapper(logger)
|
|
42
|
+
tmpLog.info("start")
|
|
43
|
+
# loop over all vos
|
|
44
|
+
for vo in self.vos:
|
|
45
|
+
# loop over all sourceLabels
|
|
46
|
+
for prodSourceLabel in self.prodSourceLabels:
|
|
47
|
+
# prepare tasks to be finished
|
|
48
|
+
tmpLog.info(f"preparing tasks to be finished for vo={vo} label={prodSourceLabel}")
|
|
49
|
+
tmp_ret_list = self.taskBufferIF.prepareTasksToBeFinished_JEDI(vo, prodSourceLabel, jedi_config.postprocessor.nTasks, pid=self.pid)
|
|
50
|
+
if tmp_ret_list is None:
|
|
51
|
+
# failed
|
|
52
|
+
tmpLog.error("failed to prepare tasks")
|
|
53
|
+
# get tasks to be finished
|
|
54
|
+
tmpLog.info("getting tasks to be finished")
|
|
55
|
+
tmpList = self.taskBufferIF.getTasksToBeFinished_JEDI(
|
|
56
|
+
vo, prodSourceLabel, self.pid, jedi_config.postprocessor.nTasks, target_tasks=tmp_ret_list
|
|
57
|
+
)
|
|
58
|
+
if tmpList is None:
|
|
59
|
+
# failed
|
|
60
|
+
tmpLog.error("failed to get tasks to be finished")
|
|
61
|
+
else:
|
|
62
|
+
tmpLog.info(f"got {len(tmpList)} tasks")
|
|
63
|
+
# put to a locked list
|
|
64
|
+
taskList = ListWithLock(tmpList)
|
|
65
|
+
# make thread pool
|
|
66
|
+
threadPool = ThreadPool()
|
|
67
|
+
# make workers
|
|
68
|
+
nWorker = jedi_config.postprocessor.nWorkers
|
|
69
|
+
for iWorker in range(nWorker):
|
|
70
|
+
thr = PostProcessorThread(taskList, threadPool, self.taskBufferIF, self.ddmIF, self)
|
|
71
|
+
thr.start()
|
|
72
|
+
# join
|
|
73
|
+
threadPool.join()
|
|
74
|
+
tmpLog.info("done")
|
|
75
|
+
except Exception:
|
|
76
|
+
errtype, errvalue = sys.exc_info()[:2]
|
|
77
|
+
tmpLog.error(f"failed in {self.__class__.__name__}.start() with {errtype.__name__} {errvalue}")
|
|
78
|
+
# sleep if needed
|
|
79
|
+
loopCycle = 60
|
|
80
|
+
timeDelta = naive_utcnow() - startTime
|
|
81
|
+
sleepPeriod = loopCycle - timeDelta.seconds
|
|
82
|
+
if sleepPeriod > 0:
|
|
83
|
+
time.sleep(sleepPeriod)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# thread for real worker
|
|
87
|
+
class PostProcessorThread(WorkerThread):
|
|
88
|
+
# constructor
|
|
89
|
+
def __init__(self, taskList, threadPool, taskbufferIF, ddmIF, implFactory):
|
|
90
|
+
# initialize woker with no semaphore
|
|
91
|
+
WorkerThread.__init__(self, None, threadPool, logger)
|
|
92
|
+
# attributres
|
|
93
|
+
self.taskList = taskList
|
|
94
|
+
self.taskBufferIF = taskbufferIF
|
|
95
|
+
self.ddmIF = ddmIF
|
|
96
|
+
self.implFactory = implFactory
|
|
97
|
+
|
|
98
|
+
# post process tasks
|
|
99
|
+
def post_process_tasks(self, task_list):
|
|
100
|
+
for taskSpec in task_list:
|
|
101
|
+
# make logger
|
|
102
|
+
tmpLog = MsgWrapper(self.logger, f"<jediTaskID={taskSpec.jediTaskID}>")
|
|
103
|
+
tmpLog.info("start")
|
|
104
|
+
tmpStat = Interaction.SC_SUCCEEDED
|
|
105
|
+
# get impl
|
|
106
|
+
impl = self.implFactory.instantiateImpl(taskSpec.vo, taskSpec.prodSourceLabel, None, self.taskBufferIF, self.ddmIF)
|
|
107
|
+
if impl is None:
|
|
108
|
+
# post processor is undefined
|
|
109
|
+
tmpLog.error(f"post-processor is undefined for vo={taskSpec.vo} sourceLabel={taskSpec.prodSourceLabel}")
|
|
110
|
+
tmpStat = Interaction.SC_FATAL
|
|
111
|
+
# execute
|
|
112
|
+
if tmpStat == Interaction.SC_SUCCEEDED:
|
|
113
|
+
tmpLog.info(f"post-process with {impl.__class__.__name__}")
|
|
114
|
+
try:
|
|
115
|
+
tmpStat = impl.doPostProcess(taskSpec, tmpLog)
|
|
116
|
+
except Exception as e:
|
|
117
|
+
tmpLog.error(f"post-process failed with {str(e)}")
|
|
118
|
+
tmpStat = Interaction.SC_FATAL
|
|
119
|
+
# done
|
|
120
|
+
if tmpStat == Interaction.SC_FATAL or (tmpStat == Interaction.SC_FAILED and taskSpec.status in ["toabort", "tobroken"]):
|
|
121
|
+
# task is broken
|
|
122
|
+
tmpErrStr = "post-process permanently failed"
|
|
123
|
+
tmpLog.error(tmpErrStr)
|
|
124
|
+
taskSpec.status = "broken"
|
|
125
|
+
taskSpec.setErrDiag(tmpErrStr)
|
|
126
|
+
taskSpec.lockedBy = None
|
|
127
|
+
self.taskBufferIF.updateTask_JEDI(taskSpec, {"jediTaskID": taskSpec.jediTaskID})
|
|
128
|
+
elif tmpStat == Interaction.SC_FAILED:
|
|
129
|
+
tmpErrStr = "post-processing temporarily failed"
|
|
130
|
+
taskSpec.setErrDiag(tmpErrStr, True)
|
|
131
|
+
self.taskBufferIF.updateTask_JEDI(taskSpec, {"jediTaskID": taskSpec.jediTaskID})
|
|
132
|
+
tmpLog.info(f"set task_status={taskSpec.status} since {taskSpec.errorDialog}")
|
|
133
|
+
tmpLog.info("done")
|
|
134
|
+
continue
|
|
135
|
+
# final procedure
|
|
136
|
+
try:
|
|
137
|
+
impl.doFinalProcedure(taskSpec, tmpLog)
|
|
138
|
+
except Exception as e:
|
|
139
|
+
tmpLog.error(f"final procedure failed with {str(e)}")
|
|
140
|
+
# done
|
|
141
|
+
tmpLog.info("done")
|
|
142
|
+
|
|
143
|
+
# main
|
|
144
|
+
def runImpl(self):
|
|
145
|
+
while True:
|
|
146
|
+
try:
|
|
147
|
+
# get a part of list
|
|
148
|
+
nTasks = 10
|
|
149
|
+
taskList = self.taskList.get(nTasks)
|
|
150
|
+
# no more datasets
|
|
151
|
+
if len(taskList) == 0:
|
|
152
|
+
self.logger.debug(f"{self.__class__.__name__} terminating since no more items")
|
|
153
|
+
return
|
|
154
|
+
# post process tasks
|
|
155
|
+
self.post_process_tasks(taskList)
|
|
156
|
+
except Exception:
|
|
157
|
+
errtype, errvalue = sys.exc_info()[:2]
|
|
158
|
+
logger.error(f"{self.__class__.__name__} failed in runImpl() with {errtype.__name__}:{errvalue}")
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
# launch
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def launcher(commuChannel, taskBufferIF, ddmIF, vos=None, prodSourceLabels=None):
|
|
165
|
+
p = PostProcessor(commuChannel, taskBufferIF, ddmIF, vos, prodSourceLabels)
|
|
166
|
+
p.start()
|