@Override
    public void run() {
        if (backgroundJobServer.isNotReadyToProcessJobs()) return;

        try (PeriodicTaskRunInfo runInfo = taskStatistics.startRun(backgroundJobServerConfiguration())) {
            tasks.forEach(task -> task.run(runInfo));
            runInfo.markRunAsSucceeded();
        } catch (Exception e) {
            taskStatistics.handleException(e);
            if (taskStatistics.hasTooManyExceptions()) {
                if (e instanceof StorageException) {
                    LOGGER.error("FATAL - JobRunr encountered too many storage exceptions. Shutting down. Did you know JobRunr Pro has built-in database fault tolerance? Check out https://www.jobrunr.io/en/documentation/pro/database-fault-tolerance/", e);
                } else {
                    LOGGER.error("FATAL - JobRunr encountered too many processing exceptions. Shutting down.", shouldNotHappenException(e));
                }
                backgroundJobServer.stop();
            } else {
                LOGGER.warn(JobRunrException.SHOULD_NOT_HAPPEN_MESSAGE + " - Processing will continue.", e);
            }
        }
    }
@Test
    void severeJobRunrExceptionsAreLoggedToStorageProvider() {
        Task mockedTask = mockTaskThatThrows(new SevereJobRunrException("Could not resolve ConcurrentJobModificationException", new UnresolvableConcurrentJobModificationException(emptyList(), null)));
        JobHandler jobHandler = createJobHandlerWithTask(mockedTask);

        jobHandler.run();

        verify(storageProvider).saveMetadata(jobRunrMetadataArgumentCaptor.capture());

        assertThat(jobRunrMetadataArgumentCaptor.getValue())
                .hasName(SevereJobRunrException.class.getSimpleName())
                .hasOwner("BackgroundJobServer " + backgroundJobServer.getId())
                .valueContains("## Runtime information");
    }