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,513 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ConBridge allows having database interactions in separate processes and killing them independently when interactions are stalled.
|
|
3
|
+
This avoids clogged httpd processes due to stalled database accesses.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import os
|
|
7
|
+
import pickle
|
|
8
|
+
import random
|
|
9
|
+
import signal
|
|
10
|
+
import socket
|
|
11
|
+
import sys
|
|
12
|
+
import threading
|
|
13
|
+
import time
|
|
14
|
+
import traceback
|
|
15
|
+
import types
|
|
16
|
+
|
|
17
|
+
from pandacommon.pandalogger.PandaLogger import PandaLogger
|
|
18
|
+
|
|
19
|
+
from pandaserver.config import panda_config
|
|
20
|
+
from pandaserver.taskbuffer import OraDBProxy as DBProxy
|
|
21
|
+
from pandaserver.taskbuffer.DatasetSpec import DatasetSpec
|
|
22
|
+
from pandaserver.taskbuffer.FileSpec import FileSpec
|
|
23
|
+
from pandaserver.taskbuffer.JobSpec import JobSpec
|
|
24
|
+
|
|
25
|
+
# logger
|
|
26
|
+
_logger = PandaLogger().getLogger("ConBridge")
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# exception for normal termination
|
|
30
|
+
class HarmlessEx(Exception):
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# terminate child process by itself when master has gone
|
|
35
|
+
class Terminator(threading.Thread):
|
|
36
|
+
# constructor
|
|
37
|
+
def __init__(self, consock):
|
|
38
|
+
threading.Thread.__init__(self)
|
|
39
|
+
self.consock = consock
|
|
40
|
+
|
|
41
|
+
# main
|
|
42
|
+
def run(self):
|
|
43
|
+
# watching control socket
|
|
44
|
+
try:
|
|
45
|
+
rcvSize = self.consock.recv(1)
|
|
46
|
+
except Exception:
|
|
47
|
+
pass
|
|
48
|
+
# get PID
|
|
49
|
+
pid = os.getpid()
|
|
50
|
+
_logger.debug(f"child {pid} received termination")
|
|
51
|
+
# kill
|
|
52
|
+
try:
|
|
53
|
+
os.kill(pid, signal.SIGTERM)
|
|
54
|
+
except Exception:
|
|
55
|
+
pass
|
|
56
|
+
try:
|
|
57
|
+
os.kill(pid, signal.SIGKILL)
|
|
58
|
+
except Exception:
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# connection bridge with timeout
|
|
63
|
+
class ConBridge(object):
|
|
64
|
+
# constructor
|
|
65
|
+
def __init__(self):
|
|
66
|
+
self.child_pid = 0
|
|
67
|
+
self.isMaster = False
|
|
68
|
+
self.mysock = None
|
|
69
|
+
self.consock = None
|
|
70
|
+
self.proxy = None
|
|
71
|
+
self.pid = os.getpid()
|
|
72
|
+
# timeout
|
|
73
|
+
if hasattr(panda_config, "dbtimeout"):
|
|
74
|
+
self.timeout = int(panda_config.dbtimeout)
|
|
75
|
+
else:
|
|
76
|
+
self.timeout = 600
|
|
77
|
+
# verbose
|
|
78
|
+
if hasattr(panda_config, "dbbridgeverbose"):
|
|
79
|
+
self.verbose = panda_config.dbbridgeverbose
|
|
80
|
+
else:
|
|
81
|
+
self.verbose = False
|
|
82
|
+
|
|
83
|
+
# destructor
|
|
84
|
+
def __del__(self):
|
|
85
|
+
# kill old child process
|
|
86
|
+
self.bridge_killChild()
|
|
87
|
+
|
|
88
|
+
# connect
|
|
89
|
+
def connect(
|
|
90
|
+
self,
|
|
91
|
+
dbhost=panda_config.dbhost,
|
|
92
|
+
dbpasswd=panda_config.dbpasswd,
|
|
93
|
+
dbuser=panda_config.dbuser,
|
|
94
|
+
dbname=panda_config.dbname,
|
|
95
|
+
dbtimeout=None,
|
|
96
|
+
reconnect=False,
|
|
97
|
+
):
|
|
98
|
+
# kill old child process
|
|
99
|
+
self.bridge_killChild()
|
|
100
|
+
_logger.debug(f"master {self.pid} connecting")
|
|
101
|
+
# reset child PID and sockets
|
|
102
|
+
self.child_pid = 0
|
|
103
|
+
self.mysock = None
|
|
104
|
+
self.consock = None
|
|
105
|
+
# create socket
|
|
106
|
+
datpair = socket.socketpair()
|
|
107
|
+
conpair = socket.socketpair()
|
|
108
|
+
# fork
|
|
109
|
+
self.child_pid = os.fork()
|
|
110
|
+
if self.child_pid == 0:
|
|
111
|
+
# child
|
|
112
|
+
self.isMaster = False
|
|
113
|
+
self.pid = os.getpid()
|
|
114
|
+
# keep socket
|
|
115
|
+
self.mysock = datpair[1]
|
|
116
|
+
self.consock = conpair[1]
|
|
117
|
+
datpair[0].close()
|
|
118
|
+
conpair[0].close()
|
|
119
|
+
# connect to database
|
|
120
|
+
_logger.debug(f"child {self.pid} connecting to database")
|
|
121
|
+
self.proxy = DBProxy.DBProxy()
|
|
122
|
+
if not self.proxy.connect(dbhost=dbhost, dbpasswd=dbpasswd, dbtimeout=60):
|
|
123
|
+
_logger.error(f"child {self.pid} failed to connect")
|
|
124
|
+
# send error
|
|
125
|
+
self.bridge_sendError((RuntimeError, f"child {self.pid} connection failed"))
|
|
126
|
+
# exit
|
|
127
|
+
self.bridge_childExit()
|
|
128
|
+
# send OK just for ACK
|
|
129
|
+
_logger.debug(f"child {self.pid} connection is ready")
|
|
130
|
+
self.bridge_sendResponse(None)
|
|
131
|
+
# start terminator
|
|
132
|
+
Terminator(self.consock).start()
|
|
133
|
+
# go main loop
|
|
134
|
+
_logger.debug(f"child {self.pid} going into the main loop")
|
|
135
|
+
self.bridge_run()
|
|
136
|
+
# exit
|
|
137
|
+
self.bridge_childExit(0)
|
|
138
|
+
else:
|
|
139
|
+
# master
|
|
140
|
+
self.isMaster = True
|
|
141
|
+
# keep socket
|
|
142
|
+
self.mysock = datpair[0]
|
|
143
|
+
self.consock = conpair[0]
|
|
144
|
+
datpair[1].close()
|
|
145
|
+
conpair[1].close()
|
|
146
|
+
try:
|
|
147
|
+
# get ACK
|
|
148
|
+
_logger.debug(f"master {self.pid} waiting ack from child={self.child_pid}")
|
|
149
|
+
self.bridge_getResponse()
|
|
150
|
+
_logger.debug(f"master {self.pid} got ready from child={self.child_pid}")
|
|
151
|
+
return True
|
|
152
|
+
except Exception as e:
|
|
153
|
+
_logger.error(f"master {self.pid} failed to setup child={self.child_pid} : {str(e)} {traceback.format_exc()}")
|
|
154
|
+
# kill child
|
|
155
|
+
self.bridge_killChild()
|
|
156
|
+
return False
|
|
157
|
+
|
|
158
|
+
#######################
|
|
159
|
+
# communication methods
|
|
160
|
+
|
|
161
|
+
# send packet
|
|
162
|
+
def bridge_send(self, val):
|
|
163
|
+
try:
|
|
164
|
+
# set timeout
|
|
165
|
+
if self.isMaster:
|
|
166
|
+
self.mysock.settimeout(self.timeout)
|
|
167
|
+
# serialize
|
|
168
|
+
tmpStr = pickle.dumps(val, protocol=0)
|
|
169
|
+
# send size
|
|
170
|
+
sizeStr = "%50s" % len(tmpStr)
|
|
171
|
+
self.mysock.sendall(sizeStr.encode())
|
|
172
|
+
# send body
|
|
173
|
+
self.mysock.sendall(tmpStr)
|
|
174
|
+
# set timeout back
|
|
175
|
+
if self.isMaster:
|
|
176
|
+
self.mysock.settimeout(None)
|
|
177
|
+
except Exception as e:
|
|
178
|
+
if self.isMaster:
|
|
179
|
+
roleType = "master"
|
|
180
|
+
else:
|
|
181
|
+
roleType = "child "
|
|
182
|
+
_logger.error(f"{roleType} {self.pid} send error : val={str(val)[:1024]} - {str(e)} {traceback.format_exc()}")
|
|
183
|
+
# terminate child
|
|
184
|
+
if not self.isMaster:
|
|
185
|
+
self.bridge_childExit()
|
|
186
|
+
raise e
|
|
187
|
+
|
|
188
|
+
# receive packet
|
|
189
|
+
def bridge_recv(self):
|
|
190
|
+
try:
|
|
191
|
+
# set timeout
|
|
192
|
+
if self.isMaster:
|
|
193
|
+
self.mysock.settimeout(self.timeout)
|
|
194
|
+
# get size
|
|
195
|
+
strSize = None
|
|
196
|
+
headSize = 50
|
|
197
|
+
while strSize is None or len(strSize) < headSize:
|
|
198
|
+
if strSize is None:
|
|
199
|
+
tmpSize = headSize
|
|
200
|
+
else:
|
|
201
|
+
tmpSize = headSize - len(strSize)
|
|
202
|
+
tmpStr = self.mysock.recv(tmpSize)
|
|
203
|
+
if len(tmpStr) == 0:
|
|
204
|
+
if self.isMaster:
|
|
205
|
+
raise socket.error("empty packet")
|
|
206
|
+
else:
|
|
207
|
+
# master closed socket
|
|
208
|
+
raise HarmlessEx("empty packet")
|
|
209
|
+
if strSize is None:
|
|
210
|
+
strSize = tmpStr
|
|
211
|
+
else:
|
|
212
|
+
strSize += tmpStr
|
|
213
|
+
if strSize is None:
|
|
214
|
+
strSize = ""
|
|
215
|
+
else:
|
|
216
|
+
strSize = strSize.decode()
|
|
217
|
+
# get body
|
|
218
|
+
strBody = None
|
|
219
|
+
bodySize = int(strSize)
|
|
220
|
+
while strBody is None or len(strBody) < bodySize:
|
|
221
|
+
if strBody is None:
|
|
222
|
+
tmpSize = bodySize
|
|
223
|
+
else:
|
|
224
|
+
tmpSize = bodySize - len(strBody)
|
|
225
|
+
tmpStr = self.mysock.recv(tmpSize)
|
|
226
|
+
if len(tmpStr) == 0:
|
|
227
|
+
if self.isMaster:
|
|
228
|
+
raise socket.error("empty packet")
|
|
229
|
+
else:
|
|
230
|
+
# master closed socket
|
|
231
|
+
raise HarmlessEx("empty packet")
|
|
232
|
+
if strBody is None:
|
|
233
|
+
strBody = tmpStr
|
|
234
|
+
else:
|
|
235
|
+
strBody += tmpStr
|
|
236
|
+
if strBody is None:
|
|
237
|
+
strBody = "".encode()
|
|
238
|
+
# set timeout back
|
|
239
|
+
if self.isMaster:
|
|
240
|
+
self.mysock.settimeout(None)
|
|
241
|
+
# deserialize
|
|
242
|
+
retVal = pickle.loads(strBody)
|
|
243
|
+
return True, retVal
|
|
244
|
+
except Exception as e:
|
|
245
|
+
if self.isMaster:
|
|
246
|
+
roleType = "master"
|
|
247
|
+
else:
|
|
248
|
+
roleType = "child "
|
|
249
|
+
if isinstance(e, HarmlessEx):
|
|
250
|
+
_logger.debug(f"{roleType} {self.pid} recv harmless ex : {str(e)}")
|
|
251
|
+
else:
|
|
252
|
+
_logger.error(f"{roleType} {self.pid} recv error : {str(e)} {traceback.format_exc()}")
|
|
253
|
+
# terminate child
|
|
254
|
+
if not self.isMaster:
|
|
255
|
+
self.bridge_childExit()
|
|
256
|
+
raise e
|
|
257
|
+
|
|
258
|
+
#######################
|
|
259
|
+
# child's methods
|
|
260
|
+
|
|
261
|
+
# send error
|
|
262
|
+
def bridge_sendError(self, val):
|
|
263
|
+
# send status
|
|
264
|
+
self.bridge_send("NG")
|
|
265
|
+
# check if pickle-able
|
|
266
|
+
try:
|
|
267
|
+
pickle.dumps(val, protocol=0)
|
|
268
|
+
except Exception:
|
|
269
|
+
# use RuntimeError
|
|
270
|
+
val = (RuntimeError, str(val[-1]))
|
|
271
|
+
# send exceptions
|
|
272
|
+
self.bridge_send(val)
|
|
273
|
+
|
|
274
|
+
# send response
|
|
275
|
+
def bridge_sendResponse(self, val):
|
|
276
|
+
# send status
|
|
277
|
+
self.bridge_send("OK")
|
|
278
|
+
# send response
|
|
279
|
+
self.bridge_send(val)
|
|
280
|
+
|
|
281
|
+
# termination of child
|
|
282
|
+
def bridge_childExit(self, exitCode=1):
|
|
283
|
+
if not self.isMaster:
|
|
284
|
+
# close database connection
|
|
285
|
+
_logger.debug(f"child {self.pid} closing database connection")
|
|
286
|
+
if self.proxy:
|
|
287
|
+
self.proxy.cleanup()
|
|
288
|
+
# close sockets
|
|
289
|
+
_logger.debug(f"child {self.pid} closing sockets")
|
|
290
|
+
try:
|
|
291
|
+
self.mysock.shutdown(socket.SHUT_RDWR)
|
|
292
|
+
except Exception:
|
|
293
|
+
pass
|
|
294
|
+
try:
|
|
295
|
+
self.consock.shutdown(socket.SHUT_RDWR)
|
|
296
|
+
except Exception:
|
|
297
|
+
pass
|
|
298
|
+
# exit
|
|
299
|
+
_logger.debug(f"child {self.pid} going to exit")
|
|
300
|
+
os._exit(exitCode)
|
|
301
|
+
|
|
302
|
+
# child main
|
|
303
|
+
def bridge_run(self):
|
|
304
|
+
comStr = ""
|
|
305
|
+
while True:
|
|
306
|
+
try:
|
|
307
|
+
# get command
|
|
308
|
+
status, comStr = self.bridge_recv()
|
|
309
|
+
if not status:
|
|
310
|
+
raise RuntimeError("invalid command")
|
|
311
|
+
# get variables
|
|
312
|
+
status, variables = self.bridge_recv()
|
|
313
|
+
if not status:
|
|
314
|
+
raise RuntimeError("invalid variables")
|
|
315
|
+
except Exception:
|
|
316
|
+
errType, errValue = sys.exc_info()[:2]
|
|
317
|
+
_logger.error(f"child {self.pid} died : {errType} {errValue}")
|
|
318
|
+
# exit
|
|
319
|
+
self.bridge_childExit()
|
|
320
|
+
if self.verbose:
|
|
321
|
+
_logger.debug(f"child {self.pid} method {comStr} executing")
|
|
322
|
+
try:
|
|
323
|
+
# execute
|
|
324
|
+
method = getattr(self.proxy, comStr)
|
|
325
|
+
res = method(*variables[0], **variables[1])
|
|
326
|
+
# FIXME : modify response since oracledb types cannot be picked
|
|
327
|
+
if comStr in ["querySQLS"]:
|
|
328
|
+
newRes = [True] + list(res[1:])
|
|
329
|
+
res = newRes
|
|
330
|
+
if self.verbose:
|
|
331
|
+
_logger.debug(f"child {self.pid} method {comStr} completed")
|
|
332
|
+
# return
|
|
333
|
+
self.bridge_sendResponse((res, variables[0], variables[1]))
|
|
334
|
+
except Exception:
|
|
335
|
+
errType, errValue = sys.exc_info()[:2]
|
|
336
|
+
_logger.error(f"child {self.pid} method {comStr} failed : {errType} {errValue}")
|
|
337
|
+
if errType in [socket.error, socket.timeout]:
|
|
338
|
+
_logger.error(f"child {self.pid} died : {errType} {errValue}")
|
|
339
|
+
# exit
|
|
340
|
+
self.bridge_childExit()
|
|
341
|
+
# send error
|
|
342
|
+
self.bridge_sendError((errType, errValue))
|
|
343
|
+
|
|
344
|
+
#######################
|
|
345
|
+
# master's methods
|
|
346
|
+
|
|
347
|
+
# kill child
|
|
348
|
+
def bridge_killChild(self):
|
|
349
|
+
# kill old child process
|
|
350
|
+
if self.child_pid != 0:
|
|
351
|
+
# close sockets
|
|
352
|
+
_logger.debug(f"master {self.pid} closing sockets for child={self.child_pid}")
|
|
353
|
+
try:
|
|
354
|
+
if self.mysock is not None:
|
|
355
|
+
self.mysock.shutdown(socket.SHUT_RDWR)
|
|
356
|
+
except Exception:
|
|
357
|
+
pass
|
|
358
|
+
try:
|
|
359
|
+
if self.consock is not None:
|
|
360
|
+
self.consock.shutdown(socket.SHUT_RDWR)
|
|
361
|
+
except Exception:
|
|
362
|
+
pass
|
|
363
|
+
_logger.debug(f"master {self.pid} killing child={self.child_pid}")
|
|
364
|
+
# send SIGTERM
|
|
365
|
+
try:
|
|
366
|
+
os.kill(self.child_pid, signal.SIGTERM)
|
|
367
|
+
except Exception:
|
|
368
|
+
pass
|
|
369
|
+
time.sleep(2)
|
|
370
|
+
# send SIGKILL
|
|
371
|
+
try:
|
|
372
|
+
os.kill(self.child_pid, signal.SIGKILL)
|
|
373
|
+
except Exception:
|
|
374
|
+
pass
|
|
375
|
+
# wait for completion of child
|
|
376
|
+
_logger.debug(f"master {self.pid} waiting child={self.child_pid}")
|
|
377
|
+
try:
|
|
378
|
+
os.waitpid(self.child_pid, 0)
|
|
379
|
+
except Exception:
|
|
380
|
+
pass
|
|
381
|
+
# sleep to avoid burst reconnection
|
|
382
|
+
time.sleep(random.randint(5, 15))
|
|
383
|
+
_logger.debug(f"master {self.pid} killed child={self.child_pid}")
|
|
384
|
+
|
|
385
|
+
# get response
|
|
386
|
+
def bridge_getResponse(self):
|
|
387
|
+
# get status
|
|
388
|
+
status, strStatus = self.bridge_recv()
|
|
389
|
+
if not status:
|
|
390
|
+
raise RuntimeError(f"master {self.pid} got invalid status response from child={self.child_pid}")
|
|
391
|
+
if strStatus == "OK":
|
|
392
|
+
# return res
|
|
393
|
+
status, ret = self.bridge_recv()
|
|
394
|
+
if not status:
|
|
395
|
+
raise RuntimeError(f"master {self.pid} got invalid response body from child={self.child_pid}")
|
|
396
|
+
return ret
|
|
397
|
+
elif strStatus == "NG":
|
|
398
|
+
# raise error
|
|
399
|
+
status, ret = self.bridge_recv()
|
|
400
|
+
if not status:
|
|
401
|
+
raise RuntimeError(f"master {self.pid} got invalid response value from child={self.child_pid}")
|
|
402
|
+
raise ret[0](ret[1])
|
|
403
|
+
else:
|
|
404
|
+
raise RuntimeError(f"master {self.pid} got invalid response from child={self.child_pid} : {str(strStatus)}")
|
|
405
|
+
|
|
406
|
+
# method wrapper class
|
|
407
|
+
class bridge_masterMethod:
|
|
408
|
+
# constructor
|
|
409
|
+
def __init__(self, name, parent):
|
|
410
|
+
self.name = name
|
|
411
|
+
self.parent = parent
|
|
412
|
+
self.pid = os.getpid()
|
|
413
|
+
|
|
414
|
+
# copy changes in taskbuff objects to master
|
|
415
|
+
def copyTbObjChanges(self, oldPar, newPar):
|
|
416
|
+
# check they have the same type
|
|
417
|
+
if not isinstance(oldPar, type(newPar)):
|
|
418
|
+
return False
|
|
419
|
+
# copy some Specs since they are passed via ref's
|
|
420
|
+
if isinstance(oldPar, JobSpec) or isinstance(oldPar, FileSpec) or isinstance(oldPar, DatasetSpec):
|
|
421
|
+
if hasattr(oldPar, "__getstate__"):
|
|
422
|
+
tmpStat = newPar.__getstate__()
|
|
423
|
+
oldPar.__setstate__(tmpStat)
|
|
424
|
+
else:
|
|
425
|
+
tmpStat = newPar.values()
|
|
426
|
+
oldPar.pack(tmpStat)
|
|
427
|
+
return True
|
|
428
|
+
# copy Datasets
|
|
429
|
+
return False
|
|
430
|
+
|
|
431
|
+
# copy changes in objects to master
|
|
432
|
+
def copyChanges(self, oldPar, newPar):
|
|
433
|
+
if isinstance(oldPar, list):
|
|
434
|
+
# delete all elements first
|
|
435
|
+
while len(oldPar) > 0:
|
|
436
|
+
oldPar.pop()
|
|
437
|
+
# append
|
|
438
|
+
for tmpItem in newPar:
|
|
439
|
+
oldPar.append(tmpItem)
|
|
440
|
+
elif isinstance(oldPar, dict):
|
|
441
|
+
# replace
|
|
442
|
+
for tmpKey in newPar:
|
|
443
|
+
oldPar[tmpKey] = newPar[tmpKey]
|
|
444
|
+
else:
|
|
445
|
+
self.copyTbObjChanges(oldPar, newPar)
|
|
446
|
+
|
|
447
|
+
# method emulation
|
|
448
|
+
def __call__(self, *args, **keywords):
|
|
449
|
+
while True:
|
|
450
|
+
try:
|
|
451
|
+
# send command name
|
|
452
|
+
self.parent.bridge_send(self.name)
|
|
453
|
+
# send variables
|
|
454
|
+
self.parent.bridge_send((args, keywords))
|
|
455
|
+
# get response
|
|
456
|
+
retVal, newArgs, newKeywords = self.parent.bridge_getResponse()
|
|
457
|
+
# propagate child's changes in args to master
|
|
458
|
+
for idxArg, tmpArg in enumerate(args):
|
|
459
|
+
self.copyChanges(tmpArg, newArgs[idxArg])
|
|
460
|
+
# propagate child's changes in keywords to master
|
|
461
|
+
for tmpKey in keywords:
|
|
462
|
+
tmpArg = keywords[tmpKey]
|
|
463
|
+
self.copyChanges(tmpArg, newKeywords[tmpKey])
|
|
464
|
+
# return
|
|
465
|
+
return retVal
|
|
466
|
+
except Exception:
|
|
467
|
+
errType, errValue = sys.exc_info()[:2]
|
|
468
|
+
_logger.error(f"master {self.pid} method {self.name} failed : {errType} {errValue}")
|
|
469
|
+
# reconnect when socket has a problem
|
|
470
|
+
if errType not in [socket.error, socket.timeout]:
|
|
471
|
+
# kill old child process
|
|
472
|
+
self.parent.bridge_killChild()
|
|
473
|
+
_logger.error(f"master {self.pid} killed child")
|
|
474
|
+
# raise errType,errValue
|
|
475
|
+
# sleep
|
|
476
|
+
time.sleep(5)
|
|
477
|
+
# reconnect
|
|
478
|
+
try:
|
|
479
|
+
_logger.debug(f"master {self.pid} trying to reconnect")
|
|
480
|
+
is_ok = self.parent.connect()
|
|
481
|
+
if is_ok:
|
|
482
|
+
_logger.debug(f"master {self.pid} reconnect completed")
|
|
483
|
+
else:
|
|
484
|
+
_logger.debug(f"master {self.pid} reconnect failed. sleep")
|
|
485
|
+
time.sleep(120)
|
|
486
|
+
except Exception:
|
|
487
|
+
_logger.error(f"master {self.pid} connect failed. sleep")
|
|
488
|
+
time.sleep(120)
|
|
489
|
+
|
|
490
|
+
# get atter for cursor attributes
|
|
491
|
+
def __getattribute__(self, name):
|
|
492
|
+
if object.__getattribute__(self, "isMaster"):
|
|
493
|
+
try:
|
|
494
|
+
# return original attribute
|
|
495
|
+
return object.__getattribute__(self, name)
|
|
496
|
+
except Exception:
|
|
497
|
+
# append methods
|
|
498
|
+
if (
|
|
499
|
+
not name.startswith("_")
|
|
500
|
+
and hasattr(DBProxy.DBProxy, name)
|
|
501
|
+
and isinstance(
|
|
502
|
+
getattr(DBProxy.DBProxy, name),
|
|
503
|
+
(types.MethodType, types.FunctionType),
|
|
504
|
+
)
|
|
505
|
+
):
|
|
506
|
+
# get DBProxy's method wrapper
|
|
507
|
+
method = ConBridge.bridge_masterMethod(name, self)
|
|
508
|
+
# set method
|
|
509
|
+
setattr(self, name, method)
|
|
510
|
+
# return
|
|
511
|
+
return method
|
|
512
|
+
# return original attribute for child
|
|
513
|
+
return object.__getattribute__(self, name)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
pool for DBProxies
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
from Queue import Queue
|
|
8
|
+
except ImportError:
|
|
9
|
+
from queue import Queue
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
import random
|
|
13
|
+
import time
|
|
14
|
+
from contextlib import contextmanager
|
|
15
|
+
from threading import Lock
|
|
16
|
+
|
|
17
|
+
from pandacommon.pandalogger.PandaLogger import PandaLogger
|
|
18
|
+
|
|
19
|
+
from pandaserver.config import panda_config
|
|
20
|
+
from pandaserver.taskbuffer import OraDBProxy as DBProxy
|
|
21
|
+
from pandaserver.taskbuffer.ConBridge import ConBridge
|
|
22
|
+
|
|
23
|
+
# logger
|
|
24
|
+
_logger = PandaLogger().getLogger("DBProxyPool")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DBProxyPool:
|
|
28
|
+
def __init__(self, dbhost, dbpasswd, nConnection, useTimeout=False, dbProxyClass=None):
|
|
29
|
+
# crate lock for callers
|
|
30
|
+
self.lock = Lock()
|
|
31
|
+
self.callers = []
|
|
32
|
+
# create Proxies
|
|
33
|
+
_logger.debug("init")
|
|
34
|
+
self.proxyList = Queue(nConnection)
|
|
35
|
+
self.connList = []
|
|
36
|
+
for i in range(nConnection):
|
|
37
|
+
_logger.debug(f"connect -> {i} ")
|
|
38
|
+
if dbProxyClass is not None:
|
|
39
|
+
proxy = dbProxyClass()
|
|
40
|
+
elif useTimeout and hasattr(panda_config, "usedbtimeout") and panda_config.usedbtimeout is True:
|
|
41
|
+
"""
|
|
42
|
+
ConBridge allows having database interactions in separate processes and killing them independently when interactions are stalled.
|
|
43
|
+
This avoids clogged httpd processes due to stalled database accesses.
|
|
44
|
+
"""
|
|
45
|
+
proxy = ConBridge()
|
|
46
|
+
else:
|
|
47
|
+
proxy = DBProxy.DBProxy()
|
|
48
|
+
self.connList.append(proxy)
|
|
49
|
+
iTry = 0
|
|
50
|
+
while True:
|
|
51
|
+
if proxy.connect(dbhost, dbpasswd, dbtimeout=60):
|
|
52
|
+
break
|
|
53
|
+
iTry += 1
|
|
54
|
+
_logger.debug(f"failed -> {i} : try {iTry}")
|
|
55
|
+
time.sleep(random.randint(60, 90))
|
|
56
|
+
self.proxyList.put(proxy)
|
|
57
|
+
time.sleep(1)
|
|
58
|
+
# get PID
|
|
59
|
+
self.pid = os.getpid()
|
|
60
|
+
_logger.debug("ready")
|
|
61
|
+
|
|
62
|
+
# return a free proxy. this method blocks until a proxy is available
|
|
63
|
+
def getProxy(self):
|
|
64
|
+
# time how long it took to get a proxy
|
|
65
|
+
start_time = time.time()
|
|
66
|
+
|
|
67
|
+
# get proxy
|
|
68
|
+
proxy = self.proxyList.get()
|
|
69
|
+
# wake up connection
|
|
70
|
+
proxy.wakeUp()
|
|
71
|
+
|
|
72
|
+
end_time = time.time()
|
|
73
|
+
elapsed_time = end_time - start_time
|
|
74
|
+
_logger.debug(f"Getting proxy took: {elapsed_time} seconds")
|
|
75
|
+
|
|
76
|
+
return proxy
|
|
77
|
+
|
|
78
|
+
# put back a proxy
|
|
79
|
+
def putProxy(self, proxy):
|
|
80
|
+
self.proxyList.put(proxy)
|
|
81
|
+
|
|
82
|
+
# context manager for getting DBProxy
|
|
83
|
+
@contextmanager
|
|
84
|
+
def get(self):
|
|
85
|
+
proxy = self.getProxy()
|
|
86
|
+
try:
|
|
87
|
+
yield proxy
|
|
88
|
+
finally:
|
|
89
|
+
self.putProxy(proxy)
|
|
90
|
+
|
|
91
|
+
# cleanup
|
|
92
|
+
def cleanup(self):
|
|
93
|
+
_logger.debug("cleanup start")
|
|
94
|
+
[c.cleanup() for c in self.connList]
|
|
95
|
+
_logger.debug("cleanup done")
|