public static void localRunnerNotification(JobConf conf, JobStatus status) {
    JobEndStatusInfo notification = createNotification(conf, status);
    if (notification != null) {
      do {
        try {
          int code = httpNotification(notification.getUri(),
              notification.getTimeout());
          if (code != 200) {
            throw new IOException("Invalid response status code: " + code);
          }
          else {
            break;
          }
        }
        catch (IOException ioex) {
          LOG.error("Notification error [" + notification.getUri() + "]", ioex);
        }
        catch (Exception ex) {
          LOG.error("Notification error [" + notification.getUri() + "]", ex);
        }
        try {
          Thread.sleep(notification.getRetryInterval());
        }
        catch (InterruptedException iex) {
          LOG.error("Notification retry error [" + notification + "]", iex);
        }
      } while (notification.configureForRetry());
    }
  }
@Test
  public void testNotificationTimeout() throws InterruptedException {
    Configuration conf = new Configuration();
    // Reduce the timeout to 1 second
    conf.setInt("mapreduce.job.end-notification.timeout", 1000);

    JobStatus jobStatus = createTestJobStatus(
        "job_20130313155005308_0001", JobStatus.SUCCEEDED);
    JobConf jobConf = createTestJobConf(
        conf, 0,
        baseUrl + "delay");
    long startTime = System.currentTimeMillis();
    JobEndNotifier.localRunnerNotification(jobConf, jobStatus);
    long elapsedTime = System.currentTimeMillis() - startTime;

    // Validate params
    assertEquals(1, DelayServlet.calledTimes);
    // Make sure we timed out with time slightly above 1 second
    // (default timeout is in terms of minutes, so we'll catch the problem)
    assertTrue(elapsedTime < 2000);
  }