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,134 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from pandacommon.pandalogger import logger_utils
|
|
4
|
+
|
|
5
|
+
from pandajedi.jedimsgprocessor.base_msg_processor import BaseMsgProcPlugin
|
|
6
|
+
|
|
7
|
+
base_logger = logger_utils.setup_logger(__name__.split(".")[-1])
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# processing message processing plugin
|
|
11
|
+
class ProcessingMsgProcPlugin(BaseMsgProcPlugin):
|
|
12
|
+
def process(self, msg_obj, decoded_data=None):
|
|
13
|
+
tmp_log = logger_utils.make_logger(base_logger, token=self.get_pid(), method_name="process")
|
|
14
|
+
# start
|
|
15
|
+
tmp_log.info("start")
|
|
16
|
+
tmp_log.debug(f"sub_id={msg_obj.sub_id} ; msg_id={msg_obj.msg_id}")
|
|
17
|
+
# parse
|
|
18
|
+
if decoded_data is None:
|
|
19
|
+
# json decode
|
|
20
|
+
try:
|
|
21
|
+
msg_dict = json.loads(msg_obj.data)
|
|
22
|
+
except Exception as e:
|
|
23
|
+
err_str = f"failed to parse message json {msg_obj.data} , skipped. {e.__class__.__name__} : {e}"
|
|
24
|
+
tmp_log.error(err_str)
|
|
25
|
+
raise
|
|
26
|
+
else:
|
|
27
|
+
msg_dict = decoded_data
|
|
28
|
+
# sanity check
|
|
29
|
+
try:
|
|
30
|
+
jeditaskid = int(msg_dict["workload_id"])
|
|
31
|
+
# message type
|
|
32
|
+
msg_type = msg_dict["msg_type"]
|
|
33
|
+
if msg_type == "file_processing":
|
|
34
|
+
target_list = msg_dict["files"]
|
|
35
|
+
elif msg_type == "collection_processing":
|
|
36
|
+
target_list = msg_dict["collections"]
|
|
37
|
+
elif msg_type == "work_processing":
|
|
38
|
+
pass
|
|
39
|
+
else:
|
|
40
|
+
raise ValueError(f"invalid msg_type value: {msg_type}")
|
|
41
|
+
# relation type
|
|
42
|
+
relation_type = msg_dict.get("relation_type")
|
|
43
|
+
except Exception as e:
|
|
44
|
+
err_str = f"failed to parse message object dict {msg_dict} , skipped. {e.__class__.__name__} : {e}"
|
|
45
|
+
tmp_log.error(err_str)
|
|
46
|
+
raise
|
|
47
|
+
# run
|
|
48
|
+
try:
|
|
49
|
+
# initialize to_proceed
|
|
50
|
+
to_proceed = False
|
|
51
|
+
# type filters
|
|
52
|
+
if msg_type in ["file_processing", "collection_processing"] and relation_type in ["input"]:
|
|
53
|
+
to_proceed = True
|
|
54
|
+
# whether to proceed the targets
|
|
55
|
+
if to_proceed:
|
|
56
|
+
# initialize
|
|
57
|
+
scope_name_dict_map = {}
|
|
58
|
+
missing_files_dict = {}
|
|
59
|
+
# loop over targets
|
|
60
|
+
for target in target_list:
|
|
61
|
+
name = target["name"]
|
|
62
|
+
scope = target["scope"]
|
|
63
|
+
datasetid = target.get("external_coll_id", None)
|
|
64
|
+
fileid = target.get("external_content_id", None)
|
|
65
|
+
if (msg_type == "file_processing" and target["status"] in ["Available"]) or (
|
|
66
|
+
msg_type == "collection_processing" and target["status"] in ["Closed"]
|
|
67
|
+
):
|
|
68
|
+
scope_name_dict_map.setdefault(scope, {})
|
|
69
|
+
scope_name_dict_map[scope][name] = (datasetid, fileid)
|
|
70
|
+
elif msg_type == "file_processing" and target["status"] in ["Missing"]:
|
|
71
|
+
# missing files
|
|
72
|
+
missing_files_dict[name] = (datasetid, fileid)
|
|
73
|
+
else:
|
|
74
|
+
# got target in bad attributes, do nothing
|
|
75
|
+
tmp_log.debug(f"jeditaskid={jeditaskid}, scope={scope}, msg_type={msg_type}, status={target['status']}, did nothing for bad target")
|
|
76
|
+
pass
|
|
77
|
+
# run by each scope
|
|
78
|
+
for scope, name_dict in scope_name_dict_map.items():
|
|
79
|
+
# about files or datasets in good status
|
|
80
|
+
if msg_type == "file_processing":
|
|
81
|
+
tmp_log.debug(f"jeditaskid={jeditaskid}, scope={scope}, update about files...")
|
|
82
|
+
res = self.tbIF.updateInputFilesStaged_JEDI(jeditaskid, scope, name_dict, by="iDDS")
|
|
83
|
+
if res is None:
|
|
84
|
+
# got error and rollback in dbproxy
|
|
85
|
+
err_str = f"jeditaskid={jeditaskid}, scope={scope}, failed to update files"
|
|
86
|
+
raise RuntimeError(err_str)
|
|
87
|
+
tmp_log.info(f"jeditaskid={jeditaskid}, scope={scope}, updated {res} files")
|
|
88
|
+
elif msg_type == "collection_processing":
|
|
89
|
+
tmp_log.debug(f"jeditaskid={jeditaskid}, scope={scope}, update about datasets...")
|
|
90
|
+
res = self.tbIF.updateInputDatasetsStaged_JEDI(jeditaskid, scope, name_dict, by="iDDS")
|
|
91
|
+
if res is None:
|
|
92
|
+
# got error and rollback in dbproxy
|
|
93
|
+
err_str = f"jeditaskid={jeditaskid}, scope={scope}, failed to update datasets"
|
|
94
|
+
raise RuntimeError(err_str)
|
|
95
|
+
tmp_log.info(f"jeditaskid={jeditaskid}, scope={scope}, updated {res} datasets")
|
|
96
|
+
# send message to contents feeder if new files are staged
|
|
97
|
+
if res > 0 or msg_type == "collection_processing":
|
|
98
|
+
tmp_s, task_spec = self.tbIF.getTaskWithID_JEDI(jeditaskid)
|
|
99
|
+
if tmp_s and task_spec.is_msg_driven():
|
|
100
|
+
push_ret = self.tbIF.push_task_trigger_message("jedi_contents_feeder", jeditaskid, task_spec=task_spec)
|
|
101
|
+
if push_ret:
|
|
102
|
+
tmp_log.debug(f"pushed trigger message to jedi_contents_feeder for jeditaskid={jeditaskid}")
|
|
103
|
+
else:
|
|
104
|
+
tmp_log.warning(f"failed to push trigger message to jedi_contents_feeder for jeditaskid={jeditaskid}")
|
|
105
|
+
# check if all ok
|
|
106
|
+
if res == len(target_list):
|
|
107
|
+
tmp_log.debug(f"jeditaskid={jeditaskid}, scope={scope}, all OK")
|
|
108
|
+
elif res < len(target_list):
|
|
109
|
+
tmp_log.warning(f"jeditaskid={jeditaskid}, scope={scope}, only {res} out of {len(target_list)} done...")
|
|
110
|
+
elif res > len(target_list):
|
|
111
|
+
tmp_log.warning(f"jeditaskid={jeditaskid}, scope={scope}, strangely, {res} out of {len(target_list)} done...")
|
|
112
|
+
else:
|
|
113
|
+
tmp_log.warning(f"jeditaskid={jeditaskid}, scope={scope}, something unwanted happened...")
|
|
114
|
+
# handle missing files
|
|
115
|
+
n_missing = len(missing_files_dict)
|
|
116
|
+
if n_missing > 0:
|
|
117
|
+
res = self.tbIF.setMissingFilesAboutIdds_JEDI(jeditaskid=jeditaskid, filenames_dict=missing_files_dict)
|
|
118
|
+
if res == n_missing:
|
|
119
|
+
tmp_log.debug(f"jeditaskid={jeditaskid}, marked all {n_missing} files missing")
|
|
120
|
+
elif res < n_missing:
|
|
121
|
+
tmp_log.warning(f"jeditaskid={jeditaskid}, only {res} out of {n_missing} files marked missing...")
|
|
122
|
+
elif res > n_missing:
|
|
123
|
+
tmp_log.warning(f"jeditaskid={jeditaskid}, strangely, {res} out of {n_missing} files marked missing...")
|
|
124
|
+
else:
|
|
125
|
+
tmp_log.warning(f"jeditaskid={jeditaskid}, res={res}, something unwanted happened about missing files...")
|
|
126
|
+
else:
|
|
127
|
+
# do nothing
|
|
128
|
+
tmp_log.debug(f"jeditaskid={jeditaskid}, msg_type={msg_type}, relation_type={relation_type}, nothing done")
|
|
129
|
+
except Exception as e:
|
|
130
|
+
err_str = f"failed to process the message, skipped. {e.__class__.__name__} : {e}"
|
|
131
|
+
tmp_log.error(err_str)
|
|
132
|
+
raise
|
|
133
|
+
# done
|
|
134
|
+
tmp_log.info("done")
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import copy
|
|
2
|
+
import json
|
|
3
|
+
import re
|
|
4
|
+
import traceback
|
|
5
|
+
|
|
6
|
+
from pandacommon.pandalogger import logger_utils
|
|
7
|
+
|
|
8
|
+
from pandajedi.jediconfig import jedi_config
|
|
9
|
+
from pandajedi.jedimsgprocessor.base_msg_processor import BaseMsgProcPlugin
|
|
10
|
+
|
|
11
|
+
base_logger = logger_utils.setup_logger(__name__.split(".")[-1])
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# list of task statuses to return to iDDS
|
|
15
|
+
to_return_task_status_list = [
|
|
16
|
+
"defined",
|
|
17
|
+
"ready",
|
|
18
|
+
"scouting",
|
|
19
|
+
"pending",
|
|
20
|
+
"paused",
|
|
21
|
+
"running",
|
|
22
|
+
"prepared",
|
|
23
|
+
"done",
|
|
24
|
+
"finished",
|
|
25
|
+
"failed",
|
|
26
|
+
"broken",
|
|
27
|
+
"aborted",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
to_return_job_status_list = [
|
|
31
|
+
"pending",
|
|
32
|
+
"defined",
|
|
33
|
+
"assigned",
|
|
34
|
+
"activated",
|
|
35
|
+
"starting",
|
|
36
|
+
"running",
|
|
37
|
+
"throttled",
|
|
38
|
+
"finished",
|
|
39
|
+
"failed",
|
|
40
|
+
"cancelled",
|
|
41
|
+
"closed",
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
# status report message processing plugin
|
|
46
|
+
class StatusReportMsgProcPlugin(BaseMsgProcPlugin):
|
|
47
|
+
"""
|
|
48
|
+
Messaging status of jobs and tasks
|
|
49
|
+
Forward the incoming message to other msg_processors plugin (e.g. Kafka) if configured in params
|
|
50
|
+
Return the processed message to send to iDDS via MQ
|
|
51
|
+
"""
|
|
52
|
+
|
|
53
|
+
def initialize(self):
|
|
54
|
+
BaseMsgProcPlugin.initialize(self)
|
|
55
|
+
# forwarding plugins: incoming message will be forwarded to process method of these plugins
|
|
56
|
+
self.forwarding_plugins = []
|
|
57
|
+
forwarding_plugin_names = self.params.get("forwarding_plugins", [])
|
|
58
|
+
if "kafka" in forwarding_plugin_names:
|
|
59
|
+
# Kafka
|
|
60
|
+
from pandajedi.jedimsgprocessor.kafka_msg_processor import (
|
|
61
|
+
KafkaMsgProcPlugin,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
plugin_inst = KafkaMsgProcPlugin()
|
|
65
|
+
plugin_inst.initialize()
|
|
66
|
+
self.forwarding_plugins.append(plugin_inst)
|
|
67
|
+
|
|
68
|
+
def process(self, msg_obj):
|
|
69
|
+
tmp_log = logger_utils.make_logger(base_logger, token=self.get_pid(), method_name="process")
|
|
70
|
+
# start
|
|
71
|
+
tmp_log.info("start")
|
|
72
|
+
tmp_log.debug(f"sub_id={msg_obj.sub_id} ; msg_id={msg_obj.msg_id}")
|
|
73
|
+
# parse json
|
|
74
|
+
try:
|
|
75
|
+
msg_dict = json.loads(msg_obj.data)
|
|
76
|
+
except Exception as exc:
|
|
77
|
+
err_str = f"failed to parse message json {msg_obj.data} , skipped. {exc.__class__.__name__} : {exc} ; {traceback.format_exc()}"
|
|
78
|
+
tmp_log.error(err_str)
|
|
79
|
+
raise
|
|
80
|
+
# sanity check
|
|
81
|
+
try:
|
|
82
|
+
msg_type = msg_dict["msg_type"]
|
|
83
|
+
except Exception as e:
|
|
84
|
+
err_str = f"failed to parse message object dict {msg_dict} , skipped. {exc.__class__.__name__} : {exc} ; {traceback.format_exc()}"
|
|
85
|
+
tmp_log.error(err_str)
|
|
86
|
+
raise
|
|
87
|
+
# whether to return the message
|
|
88
|
+
to_return_message = False
|
|
89
|
+
# run different plugins according to message type
|
|
90
|
+
try:
|
|
91
|
+
# DB source name from DB schema
|
|
92
|
+
db_source_name = re.sub("_PANDA", "", jedi_config.db.schemaJEDI).lower()
|
|
93
|
+
# process according to msg_type
|
|
94
|
+
if msg_type == "task_status":
|
|
95
|
+
tmp_log.debug("task_status")
|
|
96
|
+
# forwarding
|
|
97
|
+
for plugin_inst in self.forwarding_plugins:
|
|
98
|
+
try:
|
|
99
|
+
tmp_msg_dict = copy.deepcopy(msg_dict)
|
|
100
|
+
tmp_msg_dict["db_source"] = db_source_name
|
|
101
|
+
plugin_inst.process(msg_obj, decoded_data=tmp_msg_dict)
|
|
102
|
+
except Exception as exc:
|
|
103
|
+
tmp_log.error(f"failed to process message object dict {tmp_msg_dict}; {exc.__class__.__name__} : {exc} ; {traceback.format_exc()}")
|
|
104
|
+
# only return certain statuses
|
|
105
|
+
if msg_dict.get("status") in to_return_task_status_list:
|
|
106
|
+
to_return_message = True
|
|
107
|
+
elif msg_type == "job_status":
|
|
108
|
+
tmp_log.debug("job_status")
|
|
109
|
+
# forwarding
|
|
110
|
+
for plugin_inst in self.forwarding_plugins:
|
|
111
|
+
try:
|
|
112
|
+
tmp_msg_dict = copy.deepcopy(msg_dict)
|
|
113
|
+
tmp_msg_dict["db_source"] = db_source_name
|
|
114
|
+
plugin_inst.process(msg_obj, decoded_data=tmp_msg_dict)
|
|
115
|
+
except Exception as exc:
|
|
116
|
+
tmp_log.error(f"failed to process message object dict {tmp_msg_dict}; {exc.__class__.__name__} : {exc} ; {traceback.format_exc()}")
|
|
117
|
+
# only return certain statuses
|
|
118
|
+
if msg_dict.get("status") in to_return_job_status_list:
|
|
119
|
+
to_return_message = True
|
|
120
|
+
else:
|
|
121
|
+
warn_str = f"unknown msg_type : {msg_type}"
|
|
122
|
+
tmp_log.warning(warn_str)
|
|
123
|
+
except Exception:
|
|
124
|
+
raise
|
|
125
|
+
# done
|
|
126
|
+
tmp_log.debug(f"{msg_dict}; to_return={to_return_message}")
|
|
127
|
+
tmp_log.info("done")
|
|
128
|
+
if to_return_message:
|
|
129
|
+
return msg_obj.data
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from pandacommon.pandalogger import logger_utils
|
|
4
|
+
|
|
5
|
+
from pandajedi.jedimsgprocessor.base_msg_processor import BaseMsgProcPlugin
|
|
6
|
+
|
|
7
|
+
base_logger = logger_utils.setup_logger(__name__.split(".")[-1])
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
# Tape carousel message processing plugin
|
|
11
|
+
class TapeCarouselMsgProcPlugin(BaseMsgProcPlugin):
|
|
12
|
+
def process(self, msg_obj, decoded_data=None):
|
|
13
|
+
tmp_log = logger_utils.make_logger(base_logger, token=self.get_pid(), method_name="process")
|
|
14
|
+
# start
|
|
15
|
+
tmp_log.info("start")
|
|
16
|
+
tmp_log.debug(f"sub_id={msg_obj.sub_id} ; msg_id={msg_obj.msg_id}")
|
|
17
|
+
# parse
|
|
18
|
+
if decoded_data is None:
|
|
19
|
+
# json decode
|
|
20
|
+
try:
|
|
21
|
+
msg_dict = json.loads(msg_obj.data)
|
|
22
|
+
except Exception as e:
|
|
23
|
+
err_str = f"failed to parse message json {msg_obj.data} , skipped. {e.__class__.__name__} : {e}"
|
|
24
|
+
tmp_log.error(err_str)
|
|
25
|
+
raise
|
|
26
|
+
else:
|
|
27
|
+
msg_dict = decoded_data
|
|
28
|
+
# sanity check
|
|
29
|
+
try:
|
|
30
|
+
jeditaskid = int(msg_dict["workload_id"])
|
|
31
|
+
# message type
|
|
32
|
+
msg_type = msg_dict["msg_type"]
|
|
33
|
+
if msg_type == "file_stagein":
|
|
34
|
+
target_list = msg_dict["files"]
|
|
35
|
+
elif msg_type == "collection_stagein":
|
|
36
|
+
target_list = msg_dict["collections"]
|
|
37
|
+
elif msg_type == "work_stagein":
|
|
38
|
+
pass
|
|
39
|
+
else:
|
|
40
|
+
raise ValueError(f"invalid msg_type value: {msg_type}")
|
|
41
|
+
# relation type
|
|
42
|
+
relation_type = msg_dict.get("relation_type")
|
|
43
|
+
except Exception as e:
|
|
44
|
+
err_str = f"failed to parse message object dict {msg_dict} , skipped. {e.__class__.__name__} : {e}"
|
|
45
|
+
tmp_log.error(err_str)
|
|
46
|
+
raise
|
|
47
|
+
# run
|
|
48
|
+
try:
|
|
49
|
+
# initialize to_proceed
|
|
50
|
+
to_proceed = False
|
|
51
|
+
# type filters
|
|
52
|
+
if msg_type in ["file_stagein", "collection_stagein"] and relation_type in ["output"]:
|
|
53
|
+
to_proceed = True
|
|
54
|
+
# whether to proceed the targets
|
|
55
|
+
if to_proceed:
|
|
56
|
+
# map
|
|
57
|
+
scope_name_dict_map = {}
|
|
58
|
+
# loop over targets
|
|
59
|
+
for target in target_list:
|
|
60
|
+
name = target["name"]
|
|
61
|
+
scope = target["scope"]
|
|
62
|
+
datasetid = target.get("external_coll_id", None)
|
|
63
|
+
fileid = target.get("external_content_id", None)
|
|
64
|
+
if (msg_type == "file_stagein" and target["status"] in ["Available"]) or (
|
|
65
|
+
msg_type == "collection_stagein" and target["status"] in ["Closed"]
|
|
66
|
+
):
|
|
67
|
+
scope_name_dict_map.setdefault(scope, {})
|
|
68
|
+
scope_name_dict_map[scope][name] = (datasetid, fileid)
|
|
69
|
+
else:
|
|
70
|
+
# got target in bad attributes, do nothing
|
|
71
|
+
tmp_log.debug(f"jeditaskid={jeditaskid}, scope={scope}, msg_type={msg_type}, status={target['status']}, did nothing for bad target")
|
|
72
|
+
pass
|
|
73
|
+
# run by each scope
|
|
74
|
+
for scope, name_dict in scope_name_dict_map.items():
|
|
75
|
+
# about files or datasets in good status
|
|
76
|
+
if msg_type == "file_stagein":
|
|
77
|
+
tmp_log.debug(f"jeditaskid={jeditaskid}, scope={scope}, update about files...")
|
|
78
|
+
res = self.tbIF.updateInputFilesStaged_JEDI(jeditaskid, scope, name_dict, by="iDDS")
|
|
79
|
+
if res is None:
|
|
80
|
+
# got error and rollback in dbproxy
|
|
81
|
+
err_str = f"jeditaskid={jeditaskid}, scope={scope}, failed to update files"
|
|
82
|
+
raise RuntimeError(err_str)
|
|
83
|
+
tmp_log.info(f"jeditaskid={jeditaskid}, scope={scope}, updated {res} files")
|
|
84
|
+
elif msg_type == "collection_stagein":
|
|
85
|
+
tmp_log.debug(f"jeditaskid={jeditaskid}, scope={scope}, update about datasets...")
|
|
86
|
+
res = self.tbIF.updateInputDatasetsStaged_JEDI(jeditaskid, scope, name_dict, by="iDDS")
|
|
87
|
+
if res is None:
|
|
88
|
+
# got error and rollback in dbproxy
|
|
89
|
+
err_str = f"jeditaskid={jeditaskid}, scope={scope}, failed to update datasets"
|
|
90
|
+
raise RuntimeError(err_str)
|
|
91
|
+
tmp_log.info(f"jeditaskid={jeditaskid}, scope={scope}, updated {res} datasets")
|
|
92
|
+
# send message to contents feeder if new files are staged
|
|
93
|
+
if res > 0 or msg_type == "collection_stagein":
|
|
94
|
+
tmp_s, task_spec = self.tbIF.getTaskWithID_JEDI(jeditaskid)
|
|
95
|
+
if tmp_s and task_spec.is_msg_driven():
|
|
96
|
+
push_ret = self.tbIF.push_task_trigger_message("jedi_contents_feeder", jeditaskid, task_spec=task_spec)
|
|
97
|
+
if push_ret:
|
|
98
|
+
tmp_log.debug(f"pushed trigger message to jedi_contents_feeder for jeditaskid={jeditaskid}")
|
|
99
|
+
else:
|
|
100
|
+
tmp_log.warning(f"failed to push trigger message to jedi_contents_feeder for jeditaskid={jeditaskid}")
|
|
101
|
+
# check if all ok
|
|
102
|
+
if res == len(target_list):
|
|
103
|
+
tmp_log.debug(f"jeditaskid={jeditaskid}, scope={scope}, all OK")
|
|
104
|
+
elif res < len(target_list):
|
|
105
|
+
tmp_log.warning(f"jeditaskid={jeditaskid}, scope={scope}, only {res} out of {len(target_list)} done...")
|
|
106
|
+
elif res > len(target_list):
|
|
107
|
+
tmp_log.warning(f"jeditaskid={jeditaskid}, scope={scope}, strangely, {res} out of {len(target_list)} done...")
|
|
108
|
+
else:
|
|
109
|
+
tmp_log.warning(f"jeditaskid={jeditaskid}, scope={scope}, something unwanted happened...")
|
|
110
|
+
else:
|
|
111
|
+
# do nothing
|
|
112
|
+
tmp_log.debug(f"jeditaskid={jeditaskid}, msg_type={msg_type}, relation_type={relation_type}, nothing done")
|
|
113
|
+
except Exception as e:
|
|
114
|
+
err_str = f"failed to process the message, skipped. {e.__class__.__name__} : {e}"
|
|
115
|
+
tmp_log.error(err_str)
|
|
116
|
+
raise
|
|
117
|
+
# done
|
|
118
|
+
tmp_log.info("done")
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from pandacommon.pandalogger import logger_utils
|
|
4
|
+
|
|
5
|
+
from pandajedi.jedimsgprocessor.base_msg_processor import BaseMsgProcPlugin
|
|
6
|
+
from pandaserver.workflow.workflow_core import WorkflowInterface
|
|
7
|
+
|
|
8
|
+
base_logger = logger_utils.setup_logger(__name__.split(".")[-1])
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Workflow manager message processor plugin
|
|
12
|
+
class WorkflowManagerMsgProcPlugin(BaseMsgProcPlugin):
|
|
13
|
+
"""
|
|
14
|
+
Message-driven workflow manager
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def initialize(self):
|
|
18
|
+
"""
|
|
19
|
+
Initialize the plugin
|
|
20
|
+
"""
|
|
21
|
+
BaseMsgProcPlugin.initialize(self)
|
|
22
|
+
self.workflow_interface = WorkflowInterface(self.tbIF)
|
|
23
|
+
|
|
24
|
+
def process(self, msg_obj):
|
|
25
|
+
"""
|
|
26
|
+
Process the message
|
|
27
|
+
Typical message data looks like:
|
|
28
|
+
{"msg_type":"workflow", "workflow_id": 123, "timestamp": 987654321}
|
|
29
|
+
{"msg_type":"wfstep", "step_id": 456, "timestamp": 987654321}
|
|
30
|
+
{"msg_type":"wfdata", "data_id": 789, "timestamp": 987654321}
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
msg_obj: message object
|
|
34
|
+
"""
|
|
35
|
+
tmp_log = logger_utils.make_logger(base_logger, token=self.get_pid(), method_name="process")
|
|
36
|
+
# start
|
|
37
|
+
tmp_log.info("start")
|
|
38
|
+
tmp_log.debug(f"sub_id={msg_obj.sub_id} ; msg_id={msg_obj.msg_id}")
|
|
39
|
+
# parse json
|
|
40
|
+
try:
|
|
41
|
+
msg_dict = json.loads(msg_obj.data)
|
|
42
|
+
except Exception as e:
|
|
43
|
+
err_str = f"failed to parse message json {msg_obj.data} , skipped. {e.__class__.__name__} : {e}"
|
|
44
|
+
tmp_log.error(err_str)
|
|
45
|
+
raise
|
|
46
|
+
# sanity check
|
|
47
|
+
try:
|
|
48
|
+
msg_type = msg_dict["msg_type"]
|
|
49
|
+
except Exception as e:
|
|
50
|
+
err_str = f"failed to parse message object dict {msg_dict} , skipped. {e.__class__.__name__} : {e}"
|
|
51
|
+
tmp_log.error(err_str)
|
|
52
|
+
raise
|
|
53
|
+
if msg_type not in ("workflow", "wfstep", "wfdata"):
|
|
54
|
+
err_str = f"got unknown msg_type {msg_type} , skipped "
|
|
55
|
+
tmp_log.error(err_str)
|
|
56
|
+
raise
|
|
57
|
+
# run
|
|
58
|
+
try:
|
|
59
|
+
tmp_log.info(f"got message {msg_dict}")
|
|
60
|
+
if msg_type == "workflow":
|
|
61
|
+
workflow_id = msg_dict["workflow_id"]
|
|
62
|
+
workflow_spec = self.tbIF.get_workflow(workflow_id)
|
|
63
|
+
if workflow_spec is None:
|
|
64
|
+
tmp_log.warning(f"workflow_id={workflow_id} not found; skipped")
|
|
65
|
+
return
|
|
66
|
+
stats, workflow_spec = self.workflow_interface.process_workflow(workflow_spec, by="msg")
|
|
67
|
+
tmp_log.info(f"processed workflow_id={workflow_id}")
|
|
68
|
+
elif msg_type == "wfstep":
|
|
69
|
+
step_id = msg_dict["step_id"]
|
|
70
|
+
step_spec = self.tbIF.get_workflow_step(step_id)
|
|
71
|
+
if step_spec is None:
|
|
72
|
+
tmp_log.warning(f"step_id={step_id} not found; skipped")
|
|
73
|
+
return
|
|
74
|
+
stats, step_spec = self.workflow_interface.process_step(step_spec, by="msg")
|
|
75
|
+
tmp_log.info(f"processed step_id={step_id}")
|
|
76
|
+
elif msg_type == "wfdata":
|
|
77
|
+
data_id = msg_dict["data_id"]
|
|
78
|
+
data_spec = self.tbIF.get_workflow_data(data_id)
|
|
79
|
+
if data_spec is None:
|
|
80
|
+
tmp_log.warning(f"data_id={data_id} not found; skipped")
|
|
81
|
+
return
|
|
82
|
+
stats, data_spec = self.workflow_interface.process_data(data_spec, by="msg")
|
|
83
|
+
tmp_log.info(f"processed data_id={data_id}")
|
|
84
|
+
except Exception as e:
|
|
85
|
+
err_str = f"failed to run, skipped. {e.__class__.__name__} : {e}"
|
|
86
|
+
tmp_log.error(err_str)
|
|
87
|
+
raise
|
|
88
|
+
# done
|
|
89
|
+
tmp_log.info("done")
|