class WebsocketServer(PyThread): def __init__(self, port, app, max_connections=10, max_queued=30, **ws_args): PyThread.__init__(self) self.Port = port self.HandlerQueue = TaskQueue(max_connections, capacity=max_queued) self.App = app self.WSArgs = ws_args def run(self): srv_sock = socket(AF_INET, SOCK_STREAM) srv_sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) srv_sock.bind(("", self.Port)) srv_sock.listen(5) while True: sock, address = srv_sock.accept() receiver = WebsocketClientConnection(self.App, sock, address, self.WSArgs) try: self.HandlerQueue.addTask(receiver) except: # ws response here ! sock.close()
class ReplicationManager(Primitive, Logged): def __init__(self, cfg): Primitive.__init__(self) self.Replicators = TaskQueue(cfg.get('max_rep', 2), stagger=0.5) self.DClient = DataClient((cfg["broadcast"], cfg["listen_port"]), cfg["farm_name"]) def replicate(self, nfrep, lfn, lpath, info): if nfrep > 2: # make 2 replicators n1 = nfrep // 2 n2 = nfrep - n1 r = Replicator(lfn, lpath, info, n1, self.DClient, self) self.debug('replicator created: %s *%d' % (lpath, n1)) self.Replicators.addTask(r) r = Replicator(lfn, lpath, info, n2, self.DClient, self) self.debug('replicator created: %s *%d' % (lpath, n2)) self.Replicators.addTask(r) elif nfrep > 0: r = Replicator(lfn, lpath, info, nfrep, self.DClient, self) self.Replicators.addTask(r) self.debug('replicator created: %s *%d' % (lpath, nfrep)) def done(self, rep): pass def retry(self, rep): rep.reinit() t = threading.Timer(0.1 + random.random(), self.Replicators.addTask, args=(rep, )) t.start() def statTxns(self): pending, active = self.Replocators.tasks() stats = ["RP * %s" % (x.LogPath, ) for x in active ] + ["RP I %s" % (x.LogPath, ) for x in pending] return '\n'.join(stats) + ".\n"
class QueuedApplication(Primitive, Logged): def __init__(self, config, logger=None): self.Instance = config["instance"] Primitive.__init__(self, name=f"[app {self.Instance}]") Logged.__init__(self, f"[app {self.Instance}]", logger, debug=True) self.configure(config) @synchronized def configure(self, config=None): config = config or self.Config self.Config = config reload_files = config.get("touch_reload", []) if isinstance(reload_files, str): reload_files = [reload_files] self.ReloadFileTimestamps = {path: self.mtime(path) for path in reload_files} self.Prefix = config.get("prefix", "/") self.ReplacePrefix = config.get("replace_prefix") self.Timeout = config.get("timeout", 10) saved_path = sys.path[:] saved_modules = set(sys.modules.keys()) saved_environ = os.environ.copy() try: args = None fname = config["file"] g = {} extra_path = config.get("python_path") if extra_path is not None: if isinstance(extra_path, str): extra_path = [extra_path] sys.path = extra_path + sys.path if "env" in config: os.environ.update(config["env"]) exec(open(fname, "r").read(), g) if "create" in config: args = config.get("args") app = g[config["create"]](args) else: app = g[config.get("application", "application")] self.AppArgs = args self.WSGIApp = app max_workers = config.get("max_workers", 5) queue_capacity = config.get("queue_capacity", 10) self.RequestQueue = TaskQueue(max_workers, capacity = queue_capacity, delegate=self) self.log("(re)configured") finally: sys.path = saved_path extra_modules = set(sys.modules.keys()) - set(saved_modules) #print("loadApp: removing modules:", sorted(list(extra_modules))) for m in extra_modules: del sys.modules[m] for n in set(os.environ.keys()) - set(saved_environ.keys()): del os.environ[n] os.environ.update(saved_environ) def taskFailed(self, queue, task, exc_type, exc_value, tb): self.log_error("request failed:", "\n".join(traceback.format_exception(exc_type, exc_value, tb))) def accept(self, request): header = request.HTTPHeader uri = header.URI self.debug("accept: uri:", uri, " prefix:", self.Prefix) if uri.startswith(self.Prefix): uri = uri[len(self.Prefix):] if not uri.startswith("/"): uri = "/" + uri if self.ReplacePrefix: uri = self.ReplacePrefix + uri header.replaceURI(uri) request.AppName = self.Instance self.RequestQueue.addTask(RequestTask(self.WSGIApp, request, self.Logger)) return True else: return False def mtime(self, path): try: return os.path.getmtime(path) except: return None def reloadIfNeeded(self): for path, old_timestamp in self.ReloadFileTimestamps.items(): mt = self.mtime(path) if mt is not None and mt != old_timestamp: ct = time.ctime(mt) self.log(f"file {path} was modified at {ct}") break else: return False self.configure()
class Service(Primitive, Logged): def __init__(self, config, logger=None): name = config["name"] #print("Service(): config:", config) self.ServiceName = name Primitive.__init__(self, name=f"[service {name}]") Logged.__init__(self, f"[app {name}]", logger, debug=True) self.Config = None self.Initialized = self.initialize(config) @synchronized def initialize(self, config=None): config = config or self.Config self.Config = config reload_files = config.get("touch_reload", []) if isinstance(reload_files, str): reload_files = [reload_files] self.ReloadFileTimestamps = { path: self.mtime(path) for path in reload_files } self.Prefix = config.get("prefix", "/") self.ReplacePrefix = config.get("replace_prefix") self.Timeout = config.get("timeout", 10) saved_path = sys.path[:] saved_modules = set(sys.modules.keys()) saved_environ = os.environ.copy() try: args = None if "file" in config: print( '*** Use of "file" parameter is deprecated. Use "module" instead' ) self.ScriptFileName = fname = config.get("module", config.get("file")) g = {} extra_path = config.get("python_path") if extra_path is not None: if isinstance(extra_path, str): extra_path = [extra_path] sys.path = extra_path + sys.path if "env" in config: os.environ.update(config["env"]) try: exec(open(fname, "r").read(), g) except: tb = traceback.format_exc() self.log_error(f"Error importing module {fname}:\n{tb}") return False if "create" in config: # deprecated print( '*** Use of "create" parameter is deprecated. Use "application: function()" instead' ) application = config["create"] + "()" else: application = config.get("application", "application") if application.endswith("()"): args = config.get("args") fcn_name = application[:-2] fcn = g.get(fcn_name) if fcn is None: self.log_error( f"Application creation function {fcn_name} not found in module {fname}" ) return False try: if isinstance(args, dict): app = fcn(**args) elif isinstance(args, (list, tuple)): app = fcn(*args) elif args is None: app = fcn() else: app = fcn(args) except: tb = traceback.format_exc() self.log_error( f"Error calling the application initialization function:\n{tb}" ) return False if app is None: self.log_error( f'Application creation function {fcn_name} returned None' ) return False else: app = g.get(application) if app is None: self.log_error( f'Application object "{application}" not found in {fname}' ) return False self.AppArgs = args self.WSGIApp = app max_workers = config.get("max_workers", 5) queue_capacity = config.get("queue_capacity", 10) self.RequestQueue = TaskQueue(max_workers, capacity=queue_capacity, delegate=self) self.log("initiaized") except: tb = traceback.format_exc() self.log_error(f"Error initializing application:\n{tb}") return False finally: sys.path = saved_path extra_modules = set(sys.modules.keys()) - set(saved_modules) #print("loadApp: removing modules:", sorted(list(extra_modules))) for m in extra_modules: del sys.modules[m] for n in set(os.environ.keys()) - set(saved_environ.keys()): del os.environ[n] os.environ.update(saved_environ) return True def taskFailed(self, queue, task, exc_type, exc_value, tb): self.log_error( "request failed:", "".join(traceback.format_exception(exc_type, exc_value, tb))) try: task.Request.close() except: pass def accept(self, request): #print(f"Service {self}: accept()") if not self.Initialized: return False header = request.HTTPHeader uri = header.URI self.debug("accept: uri:", uri, " prefix:", self.Prefix) #print("Sevice", self," accept: uri:", uri, " prefix:", self.Prefix) if uri.startswith(self.Prefix): uri = uri[len(self.Prefix):] if not uri.startswith("/"): uri = "/" + uri if self.ReplacePrefix: uri = self.ReplacePrefix + uri header.replaceURI(uri) request.AppName = self.ServiceName script_path = self.Prefix while script_path and script_path.endswith("/"): script_path = script_path[:-1] request.Environ["SCRIPT_NAME"] = script_path request.Environ["SCRIPT_FILENAME"] = self.ScriptFileName self.RequestQueue.addTask( RequestTask(self.WSGIApp, request, self.Logger)) #print("Service", self, " accepted") return True else: #print("Service", self, " rejected") return False def close(self): self.RequestQueue.hold() def join(self): self.RequestQueue.join() def mtime(self, path): try: return os.path.getmtime(path) except: return None def reloadIfNeeded(self): for path, old_timestamp in self.ReloadFileTimestamps.items(): mt = self.mtime(path) if mt is not None and mt != old_timestamp: ct = time.ctime(mt) self.log(f"file {path} was modified at {ct}") break else: return False self.Initialized = self.initialize()
def purgeEmptyDirs(self): if self.EmptyDirs: queue = TaskQueue(self.MaxScanners) for path in self.EmptyDirs: queue.addTask(RMDir(self.Server, path)) queue.waitUntilEmpty()
class ScannerMaster(PyThread): MAX_RECURSION_FAILED_COUNT = 5 REPORT_INTERVAL = 10.0 def __init__(self, server, root, recursive_threshold, max_scanners, timeout, quiet, display_progress, max_files = None, include_sizes=True, ignore_subdirs=[]): PyThread.__init__(self) self.RecursiveThreshold = recursive_threshold self.Server = server self.Root = canonic_path(root) self.MaxScanners = max_scanners self.Results = DEQueue() self.ScannerQueue = TaskQueue(max_scanners) self.Timeout = timeout self.Done = False self.Error = None self.Failed = False self.RootFailed = False self.Directories = set() self.RecursiveFailed = {} # parent path -> count self.Errors = {} # location -> count self.GaveUp = {} self.LastReport = time.time() self.EmptyDirs = set() self.NScanned = 0 self.NToScan = 1 self.Quiet = quiet self.DisplayProgress = display_progress and Use_tqdm and not quiet if self.DisplayProgress: self.TQ = tqdm.tqdm(total=self.NToScan, unit="dir") self.LastV = 0 self.NFiles = self.NDirectories = 0 self.MaxFiles = max_files # will stop after number of files found exceeds this number. Used for debugging self.IgnoreSubdirs = ignore_subdirs self.IgnoredFiles = self.IgnoredDirs = 0 self.IncludeSizes = include_sizes self.TotalSize = 0.0 if include_sizes else None # Megabytes def run(self): # # scan Root non-recursovely first, if failed, return immediarely # #server, location, recursive, timeout scanner_task = Scanner(self, self.Server, self.Root, self.RecursiveThreshold == 0, self.Timeout, include_sizes=self.IncludeSizes) self.ScannerQueue.addTask(scanner_task) self.ScannerQueue.waitUntilEmpty() self.Results.close() self.ScannerQueue.Delegate = None # detach for garbage collection self.ScannerQueue = None def dir_ignored(self, path): # path is expected to be canonic here relpath = relative_path(self.Root, path) ignore = any((relpath == subdir or relpath.startswith(subdir+"/")) for subdir in self.IgnoreSubdirs) return ignore def file_ignored(self, path): # path is expected to be canonic here relpath = relative_path(self.Root, path) return any(relpath.startswith(subdir+"/") for subdir in self.IgnoreSubdirs) @synchronized def addFiles(self, files): if not self.Failed: self.Results.append(('f', files)) self.NFiles += len(files) def parent(self, path): parts = path.rsplit("/", 1) if len(parts) < 2: return "/" else: return parts[0] def addDirectory(self, path, scan, allow_recursive): if scan and not self.Failed: assert path.startswith(self.Root) relpath = path[len(self.Root):] while relpath and relpath[0] == '/': relpath = relpath[1:] while relpath and relpath[-1] == '/': relpath = relpath[:-1] reldepth = 0 if not relpath else len(relpath.split('/')) parent = self.parent(path) allow_recursive = allow_recursive and (self.RecursiveThreshold is not None and reldepth >= self.RecursiveThreshold ) if self.MaxFiles is None or self.NFiles < self.MaxFiles: self.ScannerQueue.addTask( Scanner(self, self.Server, path, allow_recursive, self.Timeout, include_sizes=self.IncludeSizes) ) self.NToScan += 1 def addDirectories(self, dirs, scan=True, allow_recursive=True): if not self.Failed: self.Results.append(('d', dirs)) self.NDirectories += len(dirs) for d in dirs: d = canonic_path(d) if self.dir_ignored(d): if scan: print(d, " - ignored") self.IgnoredDirs += 1 else: self.addDirectory(d, scan, allow_recursive) self.show_progress() self.report() @synchronized def report(self): if time.time() > self.LastReport + self.REPORT_INTERVAL: waiting, active = self.ScannerQueue.tasks() #sys.stderr.write("--- Locations to scan: %d\n" % (len(active)+len(waiting),)) self.LastReport = time.time() @synchronized def scanner_failed(self, scanner, error): path = scanner.Location with self: # update error counts if scanner.WasRecursive: parent = self.parent(path) self.RecursiveFailed[parent] = self.RecursiveFailed.get(parent, 0) + 1 else: self.Errors[path] = self.Errors.get(path, 0) + 1 retry = (scanner.RecAttempts > 0) or (scanner.FlatAttempts > 0) if retry: print("resubmitted:", scanner.Location, scanner.RecAttempts, scanner.FlatAttempts) self.ScannerQueue.addTask(scanner) else: print("Gave up:", scanner.Location) self.GaveUp[scanner.Location] = error self.NScanned += 1 #sys.stderr.write("Gave up on: %s\n" % (path,)) self.show_progress() #"Error scanning %s: %s -- retrying" % (scanner.Location, error)) @synchronized def scanner_succeeded(self, location, was_recursive, files, dirs): with self: if len(files) == 0 and (was_recursive or len(dirs) == 0): self.EmptyDirs.add(location) else: if location in self.EmptyDirs: self.EmptyDirs.remove(location) if was_recursive: parent = self.parent(location) nfailed = self.RecursiveFailed.get(parent, 0) self.RecursiveFailed[parent] = nfailed - 1 self.NScanned += 1 if files: paths, sizes = zip(*files) self.addFiles(paths) #for path, size in files: # print(f"path: {path}, size:{size}") #print("total size:", sum(sizes), location) if self.IncludeSizes: self.TotalSize += sum(sizes) if dirs: paths, sizes = zip(*dirs) scan = not was_recursive allow_recursive = scan and len(dirs) > 1 self.addDirectories(paths, scan, allow_recursive) #if self.IncludeSizes: # self.TotalSize += sum(sizes) self.show_progress() def files(self): yield from self.paths('f') def paths(self, type=None): for t, lst in self.Results: if lst and (type is None or type == t): for path in lst: path = canonic_path(path) if self.file_ignored(path): self.IgnoredFiles += 1 else: if type is None: yield t, path else: yield path @synchronized def show_progress(self, message=None): if self.DisplayProgress: self.TQ.total = self.NToScan delta = max(0, self.NScanned - self.LastV) self.TQ.update(delta) self.LastV = self.NScanned enf = 0 if self.NScanned > 0: enf = int(self.NFiles * self.NToScan/self.NScanned) self.TQ.set_postfix(f=self.NFiles, ed=len(self.EmptyDirs), d=self.NDirectories, enf=enf) if message: self.TQ.write(message) @synchronized def message(self, message): if not self.Quiet: if self.DisplayProgress: self.TQ.write(message) else: print(message) sys.stdout.flush() def close_progress(self): if self.DisplayProgress: self.TQ.close() def purgeEmptyDirs(self): if self.EmptyDirs: queue = TaskQueue(self.MaxScanners) for path in self.EmptyDirs: queue.addTask(RMDir(self.Server, path)) queue.waitUntilEmpty()
print(f"No flights for {airport} (lo:[{lomin}:{lomax}], la:[{lamin}:{lamax})]") return [] timestamp = data["time"] data = [ {"icao":d[ICAO24].strip(), "callsign":d[CALL].strip(), "country":d[COUNTRY]} for d in states ] self.DB.add(timestamp, airport, data) if __name__ == "__main__": tstart = time.time() window = 20 # km db = Database("flights.sqlite") db.start() scanner_queue = TaskQueue(10, stagger=0.5) for airport in Airports.keys(): scanner_queue.addTask(ScanTask(db, airport)) scanner_queue.waitUntilEmpty() db.stop() db.join() tend = time.time() print("runtime:", tend-tstart)
class TCPServerThread(PyThread): def __init__(self, port, ip='', max_clients=None, queue_capacity=None, stagger=None, enabled=True): PyThread.__init__(self) self.Sock = None self.Clients = TaskQueue(max_clients, capacity=queue_capacity, stagger=stagger) self.Port = port self.IP = ip self.Enabled = enabled self.Shutdown = False self.LastIdle = 0.0 def run(self): self.Sock = socket(AF_INET, SOCK_STREAM) self.Sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1) self.Sock.bind((self.IP, self.Port)) if self.Enabled: self.enable() while not self.Shutdown: fd = self.Sock.fileno() #print("TCPServerThread: select...") r, w, e = select.select([fd], [fd], [fd], 1.0) #print("TCPServerThread: r,w,e:", r, w, e) if fd in r or fd in e or fd in w: csock, caddr = self.Sock.accept() task = self.createClientInterface(csock, caddr) #print ("TCPServerThread: client task created:", task) if task is not None: self.Clients.addTask(task) else: t = time.time() self.idle(t, self.LastIdle) self.LastIdle = t self.Sock.close() @synchronized def enable(self, backlog=5): if self.Sock is not None: self.Sock.listen(backlog) self.Clients.release() self.Enabled = True @synchronized def disable(self): self.Sock.listen(0) self.Clients.hold() self.Enabled = False def shutdown(self): self.Shutdown = True def waitForClients(self): self.Clients.waitUntilEmpty() # overridables def idle(self, now, last_idle): pass def createClientInterface(self, sock, addr): return None pass # virtual
-N <n> - run all <n> tasks at once """ MaxPipes = 30 NRUN = 1000 stagger = 0.1 output = None #open("/dev/null", "w") opts, args = getopt.getopt(sys.argv[1:], "m:n:s:N:") for opt, val in opts: if opt == '-m': MaxPipes = int(val) if opt == '-n': NRUN = int(val) if opt == '-s': stagger = float(val) if opt == '-N': NRUN = int(val) MaxPipes = NRUN if not args: print Usage sys.exit(1) command = args tq = TaskQueue(MaxPipes) for i in xrange(NRUN): tq.addTask(SubprocessTask(i, NRUN, command)) time.sleep(stagger) tq.waitUntilEmpty()
from pythreader import TaskQueue, Task from threading import Timer class MyTask(Task): def __init__(self, tid): Task.__init__(self) self.Id = tid def run(self): print(time.time(), self.Id, "started as instance") time.sleep(random.random() * 3) print(self.Id, "ended") def failed(self, e): print(e) q = TaskQueue(5, stagger=1.0, tasks=[MyTask(x) for x in range(10)]) q << MyTask(30) << MyTask(31) MyTask(32) >> q q += MyTask(33) Timer(3.5, lambda q: q.addTask(MyTask(40)), (q, )).start() Timer(3.51, lambda q: q.addTask(MyTask(41)), (q, )).start() Timer(3.52, lambda q: q.addTask(MyTask(42)), (q, )).start() Timer(3.53, lambda q: q.addTask(MyTask(43)), (q, )).start() Timer(3.9, lambda q: q.addTask(MyTask(44)), (q, )).start() q.waitUntilEmpty()