public static InMemoryJobService create(
      GrpcFnServer<ArtifactStagingService> stagingService,
      Function<String, String> stagingServiceTokenProvider,
      ThrowingConsumer<Exception, String> cleanupJobFn,
      JobInvoker invoker) {
    return new InMemoryJobService(
        stagingService,
        stagingServiceTokenProvider,
        cleanupJobFn,
        invoker,
        DEFAULT_MAX_INVOCATION_HISTORY);
  }
@Test
  public void testInvocationCleanup() {
    final int maxInvocationHistory = 3;
    service =
        InMemoryJobService.create(
            stagingServer, session -> "token", null, invoker, maxInvocationHistory);

    assertThat(getNumberOfInvocations(), is(0));

    Job job1 = runJob();
    assertThat(getNumberOfInvocations(), is(1));
    Job job2 = runJob();
    assertThat(getNumberOfInvocations(), is(2));
    Job job3 = runJob();
    assertThat(getNumberOfInvocations(), is(maxInvocationHistory));

    // All running invocations must be available and never be discarded
    // even if they exceed the max history size
    Job job4 = runJob();
    assertThat(getNumberOfInvocations(), is(maxInvocationHistory + 1));

    // We need to have more than maxInvocationHistory completed jobs for the cleanup to trigger
    job1.finish();
    assertThat(getNumberOfInvocations(), is(maxInvocationHistory + 1));
    job2.finish();
    assertThat(getNumberOfInvocations(), is(maxInvocationHistory + 1));
    job3.finish();
    assertThat(getNumberOfInvocations(), is(maxInvocationHistory + 1));

    // The fourth finished job exceeds maxInvocationHistory and triggers the cleanup
    job4.finish();
    assertThat(getNumberOfInvocations(), is(maxInvocationHistory));

    // Run a new job after the cleanup
    Job job5 = runJob();
    assertThat(getNumberOfInvocations(), is(maxInvocationHistory + 1));
    job5.finish();
    assertThat(getNumberOfInvocations(), is(maxInvocationHistory));
  }