Refactor: DistributedJobManager with pub/sub status change notifications (#25)

* Add pubsub to render_queue and base_worker

* Refactor: Convert ZeroconfServer to Singleton with Class Methods

* New API for subjob servers to notify parent job servers of status changes

* Refactor: Move all subjob related methods to distributed_job_manager.py

* Rewrite for wait_for_subjobs

* Fix: DistributedJobManager.find_available_servers() takes 1 positional argument but 3 were given

* DistributedJobManager should now notify / be notified abotu background job changes

* Fix the make_ready api. Change children keyname to be id@hostname so it can be unique

* Fixes

* Image sequence to movie needs to find the actual start frame

* Fix: subjob_status_change did not return a valid response

* Fix client renderer selection

* Small fix for subjob status checking

* Fix issue with divide_frames_equally

* Fix issue where downloads were not occurring

* Fix issue where old status was being reported

* Add docstrings and code cleanup
This commit is contained in:
2023-06-30 19:49:57 -05:00
committed by GitHub
parent 0b0b410e76
commit 34fbdaa4d9
12 changed files with 503 additions and 255 deletions

View File

@@ -6,68 +6,80 @@ from zeroconf import Zeroconf, ServiceInfo, ServiceBrowser, ServiceStateChange
logger = logging.getLogger()
class ZeroconfServer():
def __init__(self, service_type, server_name, server_port):
self.service_type = service_type
self.server_name = server_name
self.server_port = server_port
self.server_ip = None
self.zeroconf = Zeroconf()
self.service_info = None
self.client_cache = {}
self.properties = {}
class ZeroconfServer:
service_type = None
server_name = None
server_port = None
server_ip = None
zeroconf = Zeroconf()
service_info = None
client_cache = {}
properties = {}
def start(self, listen_only=False):
@classmethod
def configure(cls, service_type, server_name, server_port):
cls.service_type = service_type
cls.server_name = server_name
cls.server_port = server_port
@classmethod
def start(cls, listen_only=False):
if not listen_only:
self._register_service()
self._browse_services()
cls._register_service()
cls._browse_services()
def stop(self):
self._unregister_service()
self.zeroconf.close()
@classmethod
def stop(cls):
cls._unregister_service()
cls.zeroconf.close()
def _register_service(self):
self.server_ip = socket.gethostbyname(socket.gethostname())
@classmethod
def _register_service(cls):
cls.server_ip = socket.gethostbyname(socket.gethostname())
info = ServiceInfo(
self.service_type,
f"{self.server_name}.{self.service_type}",
addresses=[socket.inet_aton(self.server_ip)],
port=self.server_port,
properties=self.properties,
cls.service_type,
f"{cls.server_name}.{cls.service_type}",
addresses=[socket.inet_aton(cls.server_ip)],
port=cls.server_port,
properties=cls.properties,
)
self.service_info = info
self.zeroconf.register_service(info)
logger.info(f"Registered zeroconf service: {self.service_info.name}")
cls.service_info = info
cls.zeroconf.register_service(info)
logger.info(f"Registered zeroconf service: {cls.service_info.name}")
def _unregister_service(self):
if self.service_info:
self.zeroconf.unregister_service(self.service_info)
logger.info(f"Unregistered zeroconf service: {self.service_info.name}")
self.service_info = None
@classmethod
def _unregister_service(cls):
if cls.service_info:
cls.zeroconf.unregister_service(cls.service_info)
logger.info(f"Unregistered zeroconf service: {cls.service_info.name}")
cls.service_info = None
def _browse_services(self):
browser = ServiceBrowser(self.zeroconf, self.service_type, [self._on_service_discovered])
@classmethod
def _browse_services(cls):
browser = ServiceBrowser(cls.zeroconf, cls.service_type, [cls._on_service_discovered])
def _on_service_discovered(self, zeroconf, service_type, name, state_change):
@classmethod
def _on_service_discovered(cls, zeroconf, service_type, name, state_change):
info = zeroconf.get_service_info(service_type, name)
logger.debug(f"Zeroconf: {name} {state_change}")
if service_type == self.service_type:
if service_type == cls.service_type:
if state_change == ServiceStateChange.Added or state_change == ServiceStateChange.Updated:
self.client_cache[name] = info
cls.client_cache[name] = info
else:
self.client_cache.pop(name)
cls.client_cache.pop(name)
def found_clients(self):
return [x.split(f'.{self.service_type}')[0] for x in self.client_cache.keys()]
@classmethod
def found_clients(cls):
return [x.split(f'.{cls.service_type}')[0] for x in cls.client_cache.keys()]
# Example usage:
if __name__ == "__main__":
server = ZeroconfServer("_zordon._tcp.local.", "foobar.local", 8080)
ZeroconfServer.configure("_zordon._tcp.local.", "foobar.local", 8080)
try:
server.start()
ZeroconfServer.start()
input("Server running - Press enter to end")
finally:
server.stop()
ZeroconfServer.stop()