2

我希望在 Java 中实现一种机制,在其中产生一个任务。任务所做的实际上与这里无关,它可以通过线程或新进程来完成。

我真正需要的是:

  • 任务可设置重试N次
  • 如果任务中发生了令人讨厌的事情,产生它的父级将受到保护
  • 以上两个都应该从我身上抽象出来

有谁知道在 Java 中可以做到这一点的任何框架?

4

3 回答 3

2

我一直在考虑这个问题已经有一段时间了,终于得到了一些你可能认为有用的东西。

我们的小“框架”的第一部分是Task接口:

public interface Task {
    void work();
    void stop();
}

实现这一点,我们可以设置我们的WorkTask

public class WorkTask implements Task {
    @Override
    public void work() {
        // Do something useful...
        // might throw SomethingNastyHappenedException
    }

    @Override
    public void stop() {
        // implement as needed e.g. to break inner loops
    }

}

为了满足您能够重试的要求,我们创建了一个Wrapper类:

public class RetryingTaskWrapper implements Task {
    private Task wrappedTask;
    private int maxTries;
    private boolean running = false;

    public RetryingTaskWrapper(Task wrappedTask, int maxTries) {
        this.wrappedTask = wrappedTask;
        this.maxTries = maxTries;
    }

    @Override
    public void work() {
        running = true;
        boolean success = false;
        int tries = 0;

        while (running && !success && tries < maxTries) {
            try {
                wrappedTask.work();
                success = true;
            } catch (SomethingNastyHappenedException e) {
                // something nasty happed so retry
                tries++;
            } catch (Exception e) {
                // something even worse happened -> end
                running = false;
            }
        }

        running = false;
    }

    @Override
    public void stop() {
        running = false;
        wrappedTask.stop();
    }
}

最后,我们需要一些东西来运行我们的任务......

public class TaskRunner implements Runnable {
    private Thread thread;
    private Task task;
    private boolean running = false;

    public TaskRunner(Task task) {
        this.task = task;
    }

    public synchronized void start() {
        if (thread != null) {
            return;
        }

        thread = new Thread(this);
        thread.start();
    }

    @Override
    public void run() {
        running = true;

        if (task != null) {
            try {
                task.work();
            } catch (Exception e) {
                // log your exception
            }
        }

        thread = null;
        running = false;
    }

    public void stop() {
        if (running) {
            if (task != null) {
                task.stop();
            }
            if (thread != null) {
                thread.interrupt();
            }
        }
    }
}

现在我们所要做的就是设置一个 TaskRunner 并启动它:

WorkTask workTask = new WorkTask();
TaskRunner runner = new TaskRunner(new RetryingTaskWrapper(workTask, 5));
runner.start();

如果您只想运行WorkTask一次而不重试,也可以:

WorkTask workTask = new WorkTask();
TaskRunner runner = new TaskRunner(workTask);
runner.start();

如果你愿意,你甚至可以WorkTask在无限循环中运行你,而不必改变你WorkTask自己。您只需要创建另一个 Wrapper

public class InfiniteLoopTaskWrapper implements Task {
    private Task wrappedTask;
    private boolean running = false;

    public InfiniteLoopTaskWrapper(Task wrappedTask) {
        this.wrappedTask = wrappedTask;
    }

    @Override
    public void work() {
        running = true;

        while (running) {
            try {
                wrappedTask.work();
            } catch (SomethingNastyHappenedException e) {
                // log that something nasty happened
            } catch (Exception e) {
                // something even worse happened -> end
                running = false;
            }
        }
    }

    @Override
    public void stop() {
        running = false;
        wrappedTask.stop();
    }

}

并运行它...

WorkTask workTask = new WorkTask();
TaskRunner runner = new TaskRunner(new InfiniteLoopTaskWrapper(workTask));
runner.start();
于 2013-05-31T11:41:51.513 回答
2

Akka非常适合解决这个问题。

或者,如果您只想在不使用 Akka/actors 的情况下更好地处理故障,您可以尝试类似Sarge的东西,它以类似于 Akka 监督的方式支持重试和故障升级。

于 2013-07-24T00:19:59.653 回答
1

如果任务中发生了令人讨厌的事情,产生它的父级将受到保护

所以我猜你有3个选择。

  1. 是在另一个进程中运行任务。查看类似Get Java Runtime Process running in background 之类的内容。我不知道有什么框架可以帮助解决这个问题。这个框架不会为您节省太多代码行。

  2. 在同一个 JVM 上的另一个线程中运行。见下文。

  3. 在另一台服务器上的另一个进程中运行。您将不得不编写客户端/服务器或使用 Web 框架或RMI来进行远程处理。我不知道有任何框架会自动为您执行此操作。

就在同一个 JVM 中运行而言,我根本不会使用框架。我只需使用适当的异常处理循环运行任务:

for (int i = 0; i < retries; i++) {
   try {
      doTask();
   } catch (Throwable t) {
      // log the throwable here
   }
}

似乎框架太复杂了。如果任务内存不足,那么在另一个线程中运行它不会有帮助,您将不得不产生另一个进程来处理任务。

如果您需要它在后台运行,那么@assyliaas 关于使用线程池的初步回答是正确的方法。

于 2013-05-29T14:29:05.417 回答