def _try_lock(self, requirements, candidate): """ Function that tries to lock given candidate resource """ resource_id = candidate.get("id") try: pid_file = f"{resource_id}.pid" self.logger.debug('Trying lock using: %s', os.path.join(self._lock_folder, pid_file)) _lockable = PidFile(pidname=pid_file, piddir=self._lock_folder) _lockable.create() self.logger.info('Allocated: %s, lockfile: %s', resource_id, pid_file) def release(): nonlocal self, resource_id, _lockable self.logger.info('Release resource: %s', resource_id) _lockable.close() del self._allocations[resource_id] return Allocation(requirements=requirements, resource_info=candidate, _release=release, pid_file=_lockable.filename) except PidFileError as error: raise AssertionError('no success') from error
def acquire_lock(name): """ Attempts to acquire a lock for the name provided. """ lock = PidFile( pidname="%s.LOCK" % name, piddir=LOCK_ROOT, enforce_dotpid_postfix=False) lock.create()
class Index: """ There's a file on disc called "local state file" and it says when was the last timestamp pulled from Slack. """ def __init__(self, index_path: Path): self._index_path = index_path self._data = None self._pidfile = PidFile("index", piddir="/tmp", lock_pidfile=True) def __enter__(self): if self._data is not None: raise Exception("can only enter once") self._index_path.parent.mkdir(exist_ok=True, parents=True) self._pidfile.create() if not self._index_path.exists(): self._index_path.write_text("{}") self._data = json.load(self._index_path.open("r")) return self def __exit__(self, exception_type, exception_value, traceback): if exception_type is None: json.dump(self._data, self._index_path.open("w"), indent=4) self._pidfile.close() self._data = None def ts(self, channel: Conversation) -> Optional[datetime.datetime]: serialized = self._timestamps.get(repr(channel)) if serialized: return self._str_to_ts(serialized) def set_ts(self, channel: Conversation, ts: datetime.datetime) -> None: self._timestamps[repr(channel)] = self._ts_to_str(ts) def set_all(self, ts): for k in self._timestamps: self._timestamps[k] = self._ts_to_str(ts) @classmethod def _ts_to_str(cls, ts: datetime.datetime) -> str: return ts.strftime(cls.datetime_format) @classmethod def _str_to_ts(cls, str_datetime: str) -> datetime.datetime: return datetime.datetime.strptime(str_datetime, cls.datetime_format) @property def _timestamps(self): return self._data.setdefault('timestamps', {}) datetime_format = "%Y-%m-%d_%H:%M:%S.%f_%z"
def start(args, logger, baseguess): global routes, static_path, timers pidfile = config.get('papercup', 'pidfile') if (pidfile[0] == '/'): piddir = os.path.dirname(pidfile) pidfile = os.path.basename(pidfile) else: piddir = baseguess logger.info("") logger.info("Writing pid file: %s/%s" % (piddir, pidfile)) pf_handler = PidFile(pidname=pidfile, piddir=piddir) passed = False for _ in range(0, 10): try: pf_handler.create() tornado.autoreload.add_reload_hook(pf_handler.close) passed = True break except PidFileAlreadyRunningError: logger.info("Pid file already running, retrying...") time.sleep(0.5) except PidFileAlreadyLockedError: logger.info("Pid file already locked, retrying...") time.sleep(0.5) if not passed: logger.info("Giving up") return logger.info("") config.init_modules() config.prerun_modules() import traceback import fnmatch from importlib import import_module import inspect from papercup import handlers client = None sentry_client = None logger.info("") logger.info("Base routes...") routes = [] from papercup import handlers for route, c, tkwargs in handlers.routes: routes.append(tornado.web.URLSpec(route, c, tkwargs, None)) route_text = "Base Routes:\n" for k in routes: if isinstance(k, tornado.web.URLSpec): cname = getattr(k.handler_class, "unbound_repr", None) if cname: cname = cname() else: cname = k.handler_class route_text += " -- URLSpec(%-25s\t%s, kwargs=%r, name=%r)\n" % ( "%r," % k.regex.pattern, cname, k.kwargs, k.name) else: route_text += " -- %s\n" % str(k) logger.info(route_text) application = tornado.web.Application(routes, **config.get('papercup', 'tornado')) application.sentry_client = sentry_client application.listen(config.get('papercup', 'port'), xheaders=config.get('papercup', 'tornado', 'xheaders')) # Tornado requires a settings entry for 'static_path' in order to make use of its static_url() method within template files, even though a separate handler was defined above. However just adding the setting to the config, even though it's not used, will allow access to proper caching behavior. application.settings['static_path'] = static_path logger.info("") logger.info("Running...") logger.info("") try: tornado.ioloop.IOLoop.instance().start() finally: for f in exit_hooks: f()