如何忽略在另一个任务的run()中触发的Luigi任务的失败

时间:2018-11-28 15:51:53

标签: python etl luigi

请考虑以下任务:

import luigi


class YieldFailTaskInBatches(luigi.Task):
    def run(self):
        for i in range(5):
            yield [
                FailTask(i, j)
                for j in range(2)
            ]


class YieldAllFailTasksAtOnce(luigi.Task):
    def run(self):
        yield [
            FailTask(i, j)
            for j in range(2)
            for i in range(5)
        ]

class FailTask(luigi.Task):
    i = luigi.IntParameter()
    j = luigi.IntParameter()

    def run(self):
        print("i: %d, j: %d" % (self.i, self.j))
        if self.j > 0:
            raise Exception("i: %d, j: %d" % (self.i, self.j))

如果FailTask,则j > 0失败。 YieldFailTaskInBatches在for循环中多次产生FailTask,而YieldAllFailTasksAtOnce产生数组中的所有任务。

如果我运行YieldFailTaskInBatches,Luigi将运行在第一个循环中产生的任务,并且由于其中一个失败(i = 0, j = 1),Luigi不会产生其余任务。如果我运行YieldAllFailTasksAtOnce,Luigi将按预期运行所有任务。

我的问题是:即使某些任务失败,如何告诉路易吉继续在YieldFailTasksInBatches上运行其余任务?可能吗?

我要问的原因是我要触发约40万个任务。我不想一次触发所有任务,因为这会使Luigi花太多时间来建立每个任务的需求(他们可以(具有1到400个要求)。我当前的解决方案是分批生产,一次很少生产,但是如果其中任何一个失败,任务就会停止,而其余的则不会生产。

this issue似乎可以解决此问题,但我想知道是否还有其他方法。

1 个答案:

答案 0 :(得分:1)

这是非常骇人听闻的,但是它应该做您想要的:

class YieldAll(luigi.Task):
    def run(self):
        errors = list()
        for i in range(5):
            for j in range(2):
                try:
                    FailTask(i, j).run()
                except Exception as e:
                    errors.append(e)

        if errors:
            raise ValueError(f' all traceback: {errors}')

class FailTask(luigi.Task):
    i = luigi.IntParameter()
    j = luigi.IntParameter()

    def run(self):
        print("i: %d, j: %d" % (self.i, self.j))
        if self.j > 0:
            raise Exception("i: %d, j: %d" % (self.i, self.j))

因此,基本上,您正在luigi上下文之外运行任务。除非您输出目标,否则luigi永远不会知道任务是否运行。

luigi知道的唯一任务是YieldAll。如果任何YieldAll产生错误,则代码将捕获该错误并将YieldAll任务设置为失败状态。