2021-01-08 13:41:50 +01:00
|
|
|
From e53d50ce5fabf67eeb5344f7be9cccbb09d0179b Mon Sep 17 00:00:00 2001
|
2019-09-26 14:48:15 +02:00
|
|
|
From: =?UTF-8?q?Pablo=20Su=C3=A1rez=20Hern=C3=A1ndez?=
|
|
|
|
<psuarezhernandez@suse.com>
|
|
|
|
Date: Thu, 26 Sep 2019 10:41:06 +0100
|
|
|
|
Subject: [PATCH] Improve batch_async to release consumed memory
|
|
|
|
(bsc#1140912)
|
|
|
|
|
|
|
|
---
|
2021-01-08 13:41:50 +01:00
|
|
|
salt/cli/batch_async.py | 89 ++++++++++++++++++++++++-----------------
|
|
|
|
1 file changed, 52 insertions(+), 37 deletions(-)
|
2019-09-26 14:48:15 +02:00
|
|
|
|
|
|
|
diff --git a/salt/cli/batch_async.py b/salt/cli/batch_async.py
|
2021-01-08 13:41:50 +01:00
|
|
|
index 388b709416..0a0b8f5f83 100644
|
2019-09-26 14:48:15 +02:00
|
|
|
--- a/salt/cli/batch_async.py
|
|
|
|
+++ b/salt/cli/batch_async.py
|
2021-01-08 13:41:50 +01:00
|
|
|
@@ -2,7 +2,7 @@
|
|
|
|
Execute a job on the targeted minions by using a moving window of fixed size `batch`.
|
|
|
|
"""
|
2019-09-26 14:48:15 +02:00
|
|
|
|
2021-01-08 13:41:50 +01:00
|
|
|
-import fnmatch
|
2019-09-26 14:48:15 +02:00
|
|
|
+import gc
|
|
|
|
|
2021-01-08 13:41:50 +01:00
|
|
|
# pylint: enable=import-error,no-name-in-module,redefined-builtin
|
|
|
|
import logging
|
|
|
|
@@ -78,6 +78,7 @@ class BatchAsync:
|
2019-09-26 14:48:15 +02:00
|
|
|
self.batch_jid = jid_gen()
|
|
|
|
self.find_job_jid = jid_gen()
|
|
|
|
self.find_job_returned = set()
|
|
|
|
+ self.ended = False
|
|
|
|
self.event = salt.utils.event.get_event(
|
2021-01-08 13:41:50 +01:00
|
|
|
"master",
|
|
|
|
self.opts["sock_dir"],
|
|
|
|
@@ -88,6 +89,7 @@ class BatchAsync:
|
|
|
|
keep_loop=True,
|
|
|
|
)
|
2019-09-26 14:48:15 +02:00
|
|
|
self.scheduled = False
|
|
|
|
+ self.patterns = {}
|
|
|
|
|
|
|
|
def __set_event_handler(self):
|
2021-01-08 13:41:50 +01:00
|
|
|
ping_return_pattern = "salt/job/{}/ret/*".format(self.ping_jid)
|
|
|
|
@@ -118,7 +120,7 @@ class BatchAsync:
|
2019-09-26 14:48:15 +02:00
|
|
|
if minion in self.active:
|
|
|
|
self.active.remove(minion)
|
|
|
|
self.done_minions.add(minion)
|
|
|
|
- self.schedule_next()
|
|
|
|
+ self.event.io_loop.spawn_callback(self.schedule_next)
|
|
|
|
|
|
|
|
def _get_next(self):
|
2021-01-08 13:41:50 +01:00
|
|
|
to_run = (
|
|
|
|
@@ -132,27 +134,27 @@ class BatchAsync:
|
2019-09-26 14:48:15 +02:00
|
|
|
)
|
|
|
|
return set(list(to_run)[:next_batch_size])
|
|
|
|
|
|
|
|
- @tornado.gen.coroutine
|
|
|
|
def check_find_job(self, batch_minions, jid):
|
2021-01-08 13:41:50 +01:00
|
|
|
- find_job_return_pattern = "salt/job/{}/ret/*".format(jid)
|
|
|
|
- self.event.unsubscribe(find_job_return_pattern, match_type="glob")
|
2019-09-26 14:48:15 +02:00
|
|
|
- self.patterns.remove((find_job_return_pattern, "find_job_return"))
|
|
|
|
+ if self.event:
|
2021-01-08 13:41:50 +01:00
|
|
|
+ find_job_return_pattern = "salt/job/{}/ret/*".format(jid)
|
|
|
|
+ self.event.unsubscribe(find_job_return_pattern, match_type="glob")
|
2019-09-26 14:48:15 +02:00
|
|
|
+ self.patterns.remove((find_job_return_pattern, "find_job_return"))
|
|
|
|
|
2021-01-08 13:41:50 +01:00
|
|
|
- timedout_minions = batch_minions.difference(self.find_job_returned).difference(
|
|
|
|
- self.done_minions
|
|
|
|
- )
|
2019-09-26 14:48:15 +02:00
|
|
|
- self.timedout_minions = self.timedout_minions.union(timedout_minions)
|
|
|
|
- self.active = self.active.difference(self.timedout_minions)
|
2021-01-08 13:41:50 +01:00
|
|
|
- running = batch_minions.difference(self.done_minions).difference(
|
|
|
|
- self.timedout_minions
|
|
|
|
- )
|
|
|
|
+ timedout_minions = batch_minions.difference(
|
|
|
|
+ self.find_job_returned
|
|
|
|
+ ).difference(self.done_minions)
|
2019-09-26 14:48:15 +02:00
|
|
|
+ self.timedout_minions = self.timedout_minions.union(timedout_minions)
|
|
|
|
+ self.active = self.active.difference(self.timedout_minions)
|
2021-01-08 13:41:50 +01:00
|
|
|
+ running = batch_minions.difference(self.done_minions).difference(
|
|
|
|
+ self.timedout_minions
|
|
|
|
+ )
|
2019-09-26 14:48:15 +02:00
|
|
|
|
|
|
|
- if timedout_minions:
|
|
|
|
- self.schedule_next()
|
|
|
|
+ if timedout_minions:
|
|
|
|
+ self.schedule_next()
|
|
|
|
|
|
|
|
- if running:
|
|
|
|
- self.find_job_returned = self.find_job_returned.difference(running)
|
|
|
|
- self.event.io_loop.add_callback(self.find_job, running)
|
|
|
|
+ if running:
|
|
|
|
+ self.find_job_returned = self.find_job_returned.difference(running)
|
|
|
|
+ self.event.io_loop.spawn_callback(self.find_job, running)
|
|
|
|
|
|
|
|
@tornado.gen.coroutine
|
|
|
|
def find_job(self, minions):
|
2021-01-08 13:41:50 +01:00
|
|
|
@@ -175,18 +177,12 @@ class BatchAsync:
|
2019-09-26 14:48:15 +02:00
|
|
|
jid=jid,
|
2021-01-08 13:41:50 +01:00
|
|
|
**self.eauth
|
|
|
|
)
|
2019-09-26 14:48:15 +02:00
|
|
|
- self.event.io_loop.call_later(
|
2021-01-08 13:41:50 +01:00
|
|
|
- self.opts["gather_job_timeout"], self.check_find_job, not_done, jid
|
|
|
|
- )
|
|
|
|
+ yield tornado.gen.sleep(self.opts["gather_job_timeout"])
|
|
|
|
+ self.event.io_loop.spawn_callback(self.check_find_job, not_done, jid)
|
|
|
|
|
2019-09-26 14:48:15 +02:00
|
|
|
@tornado.gen.coroutine
|
|
|
|
def start(self):
|
|
|
|
self.__set_event_handler()
|
2021-01-08 13:41:50 +01:00
|
|
|
- # start batching even if not all minions respond to ping
|
2019-09-26 14:48:15 +02:00
|
|
|
- self.event.io_loop.call_later(
|
2021-01-08 13:41:50 +01:00
|
|
|
- self.batch_presence_ping_timeout or self.opts["gather_job_timeout"],
|
|
|
|
- self.start_batch,
|
|
|
|
- )
|
2019-09-26 14:48:15 +02:00
|
|
|
ping_return = yield self.local.run_job_async(
|
2021-01-08 13:41:50 +01:00
|
|
|
self.opts["tgt"],
|
|
|
|
"test.ping",
|
|
|
|
@@ -198,6 +194,11 @@ class BatchAsync:
|
|
|
|
**self.eauth
|
|
|
|
)
|
|
|
|
self.targeted_minions = set(ping_return["minions"])
|
|
|
|
+ # start batching even if not all minions respond to ping
|
|
|
|
+ yield tornado.gen.sleep(
|
|
|
|
+ self.batch_presence_ping_timeout or self.opts["gather_job_timeout"]
|
|
|
|
+ )
|
2019-09-26 14:48:15 +02:00
|
|
|
+ self.event.io_loop.spawn_callback(self.start_batch)
|
|
|
|
|
|
|
|
@tornado.gen.coroutine
|
|
|
|
def start_batch(self):
|
2021-01-08 13:41:50 +01:00
|
|
|
@@ -209,14 +210,18 @@ class BatchAsync:
|
2019-09-26 14:48:15 +02:00
|
|
|
"down_minions": self.targeted_minions.difference(self.minions),
|
2021-01-08 13:41:50 +01:00
|
|
|
"metadata": self.metadata,
|
2019-09-26 14:48:15 +02:00
|
|
|
}
|
2021-01-08 13:41:50 +01:00
|
|
|
- self.event.fire_event(data, "salt/batch/{}/start".format(self.batch_jid))
|
2019-09-26 14:48:15 +02:00
|
|
|
- yield self.run_next()
|
2021-01-08 13:41:50 +01:00
|
|
|
+ ret = self.event.fire_event(
|
|
|
|
+ data, "salt/batch/{}/start".format(self.batch_jid)
|
|
|
|
+ )
|
2019-09-26 14:48:15 +02:00
|
|
|
+ self.event.io_loop.spawn_callback(self.run_next)
|
|
|
|
|
|
|
|
+ @tornado.gen.coroutine
|
|
|
|
def end_batch(self):
|
2021-01-08 13:41:50 +01:00
|
|
|
left = self.minions.symmetric_difference(
|
|
|
|
self.done_minions.union(self.timedout_minions)
|
|
|
|
)
|
2019-09-26 14:48:15 +02:00
|
|
|
- if not left:
|
|
|
|
+ if not left and not self.ended:
|
|
|
|
+ self.ended = True
|
|
|
|
data = {
|
|
|
|
"available_minions": self.minions,
|
|
|
|
"down_minions": self.targeted_minions.difference(self.minions),
|
2021-01-08 13:41:50 +01:00
|
|
|
@@ -229,20 +234,26 @@ class BatchAsync:
|
2019-09-26 14:48:15 +02:00
|
|
|
for (pattern, label) in self.patterns:
|
|
|
|
if label in ["ping_return", "batch_run"]:
|
2021-01-08 13:41:50 +01:00
|
|
|
self.event.unsubscribe(pattern, match_type="glob")
|
2019-09-26 14:48:15 +02:00
|
|
|
+ del self
|
|
|
|
+ gc.collect()
|
|
|
|
+ yield
|
|
|
|
|
|
|
|
+ @tornado.gen.coroutine
|
|
|
|
def schedule_next(self):
|
|
|
|
if not self.scheduled:
|
|
|
|
self.scheduled = True
|
|
|
|
# call later so that we maybe gather more returns
|
|
|
|
- self.event.io_loop.call_later(self.batch_delay, self.run_next)
|
|
|
|
+ yield tornado.gen.sleep(self.batch_delay)
|
|
|
|
+ self.event.io_loop.spawn_callback(self.run_next)
|
|
|
|
|
|
|
|
@tornado.gen.coroutine
|
|
|
|
def run_next(self):
|
|
|
|
+ self.scheduled = False
|
|
|
|
next_batch = self._get_next()
|
|
|
|
if next_batch:
|
|
|
|
self.active = self.active.union(next_batch)
|
|
|
|
try:
|
|
|
|
- yield self.local.run_job_async(
|
|
|
|
+ ret = yield self.local.run_job_async(
|
|
|
|
next_batch,
|
2021-01-08 13:41:50 +01:00
|
|
|
self.opts["fun"],
|
|
|
|
self.opts["arg"],
|
|
|
|
@@ -254,13 +265,17 @@ class BatchAsync:
|
|
|
|
metadata=self.metadata,
|
|
|
|
)
|
2019-09-26 14:48:15 +02:00
|
|
|
|
2021-01-08 13:41:50 +01:00
|
|
|
- self.event.io_loop.call_later(
|
|
|
|
- self.opts["timeout"], self.find_job, set(next_batch)
|
|
|
|
- )
|
|
|
|
+ yield tornado.gen.sleep(self.opts["timeout"])
|
2019-09-26 14:48:15 +02:00
|
|
|
+ self.event.io_loop.spawn_callback(self.find_job, set(next_batch))
|
|
|
|
except Exception as ex:
|
|
|
|
log.error("Error in scheduling next batch: %s", ex)
|
|
|
|
self.active = self.active.difference(next_batch)
|
|
|
|
else:
|
|
|
|
- self.end_batch()
|
|
|
|
- self.scheduled = False
|
|
|
|
+ yield self.end_batch()
|
|
|
|
+ gc.collect()
|
|
|
|
yield
|
|
|
|
+
|
|
|
|
+ def __del__(self):
|
|
|
|
+ self.event = None
|
|
|
|
+ self.ioloop = None
|
|
|
|
+ gc.collect()
|
|
|
|
--
|
2021-01-08 13:41:50 +01:00
|
|
|
2.29.2
|
2019-09-26 14:48:15 +02:00
|
|
|
|
|
|
|
|