예제 #1
0
def supervisor(target, steps, signals, sleep=0.1):
    submitted = {}

    while True:

        if Try(signals.get_nowait)\
                .map_failure(queue.Empty, lambda exc: "empty")\
                .to_option()\
                .map(lambda msg: msg == "quit")\
                .otherwise(False):
            break

        steps_outstanding = 0
        new_steps_submitted = 0
        for dep, reason in target.buildnext():
            steps_outstanding += 1
            if dep not in submitted:
                steps.put((dep, reason))
                submitted[dep] = True
                new_steps_submitted += 1

        if steps_outstanding == 0:
            break

        if new_steps_submitted == 0:
            time.sleep(sleep)

    if not target.exists:
        steps.put((target, MISSING))

    elif any(target.is_older_than(p) for p in target.parents(0)):
        steps.put((target, PARENTNEWER))

    steps.put("finished")  # signal completion
    return
예제 #2
0
def worker(fn, target, reason, err_handler, max_attempts=1):
    t = Try(fn, target, reason).on_failure(err_handler)
    if t.succeeded or max_attempts <= 1:
        return t
    return worker(fn,
                  target,
                  reason,
                  err_handler,
                  max_attempts=max_attempts - 1)
예제 #3
0
 def test_failure(self):
     result = Try(lambda: 1 / 0)
     with self.assertRaises(ZeroDivisionError):
         result.result
예제 #4
0
 def test_success(self):
     result = Try(lambda: 1 + 2)
     self.assertEqual(result.result, 3)
예제 #5
0
    def test_on_failure(self):
        result = Try(lambda: 1/0)\
                    .map_failure(KeyError, lambda exc: "a")\
                    .map_failure(ZeroDivisionError, lambda exc: "b")

        self.assertEqual(result.result, "b")
예제 #6
0
    def test_args(self):
        def f(a, b, c=1):
            return a + b - c

        result = Try(f, 2, 4, c=5)
        self.assertEqual(result.result, 1)
예제 #7
0
    def orchestrator(target, max_attempts=1, onfailure="raise", nprocs=None):
        """ Perform action to build a target.

        Parameters
        ----------
        target : Dataset
            terminal dataset to build
        max_attempts : int, optional
            maximum number of times a dependency build should be attempted
        onfailure : str
            if "raise" then propagate failures
            if "print" then print traceback and continue
            if "ignore" then continue silently
        nprocs : int
            number of worker processes to use
        supervisor_sleep : int
            milliseconds that the supervisor should wait before recomputing
            dependencies. Increasing this on large graphs can mean fewer
            cycles wasted on planning.
        """

        if onfailure == 'raise':
            ehandler = raise_exc
        elif onfailure == "print":
            ehandler = lambda e: sys.stderr.write("{}\n".format(e))
        elif onfailure == "ignore":
            ehandler = lambda e: None
        else:
            raise ValueError(
                "invalid value for onfailure: '{}'".format(onfailure))

        if nprocs is None:
            nprocs = multiprocessing.cpu_count()

        signals = queue.Queue()
        steps = queue.Queue()

        th_supervisor = threading.Thread(None,
                                         supervisor,
                                         args=(target, steps, signals))
        th_supervisor.start()

        pending = []
        with ThreadPoolExecutor(max_workers=nprocs) as executor:

            def submitter(dep, reason):
                return executor.submit(worker,
                                       delegator,
                                       dep,
                                       reason,
                                       ehandler,
                                       max_attempts=max_attempts)

            while True:

                # handle outstanding futures:
                donemap = [fut.done() for fut in pending]
                completed = [
                    fut for (fut, done) in zip(pending, donemap) if done
                ]
                pending = [
                    fut for (fut, done) in zip(pending, donemap) if not done
                ]

                if any(not fut.result().succeeded for fut in completed):
                    break

                if len(pending) > 5 * nprocs:
                    # backpressure on submissions
                    time.sleep(1.0)

                else:
                    t = Try(steps.get, True, 0.1)
                    if t.succeeded:
                        if t.result == "finished":
                            break
                        pending.append(submitter(*t.result))

        signals.put("quit")
        th_supervisor.join()

        return