@Override
    protected void afterRoll(Consumer<Throwable> exceptionConsumer) {
        boolean success = false;

        String destFileName = rolledFileName;
        destFileName = pathCreator.replaceTimeVars(destFileName);
        destFileName = pathCreator.replaceUUIDVars(destFileName);
        destFileName = pathCreator.replaceFileName(destFileName, fileName);

        // Create the destination file.
        final Path destFile = dir.resolve(destFileName);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Rolling file '{}' to '{}'", getFullPath(file), getFullPath(destFile));
        }

        // Create source path.
        Path source = file;

        // Create destination path.
        Path dest = destFile;

        // If we have got valid paths for source and dest then attempt move.
        if (source != null) {
            if (Files.isRegularFile(dest)) {
                LOGGER.error("Failed to roll file '{}' to '{}' as target exists", getFullPath(file),
                        getFullPath(destFile));
            } else {
                try {
                    Files.move(source, dest);
                    if (filePermissions != null) {
                        Files.setPosixFilePermissions(dest, filePermissions);
                    }
                    success = true;
                } catch (final IOException | RuntimeException e) {
                    exceptionConsumer.accept(wrapRollException(file, destFile, e));
                }
            }
        }

        if (source != null && !success) {
            try {
                int attempt = 1;
                while (!success && attempt <= MAX_FAILED_RENAME_ATTEMPTS) {
                    // Try to rename the file to something else.
                    final String suffix = Strings.padStart(String.valueOf(attempt), 3, '0');
                    final Path failedFile = dir.resolve(file.getFileName().toString() + "." + suffix);
                    dest = failedFile;

                    if (!Files.isRegularFile(dest)) {
                        if (LOGGER.isDebugEnabled()) {
                            LOGGER.debug("Renaming file '{}' to '{}'", getFullPath(file), getFullPath(failedFile));
                        }
                        try {
                            Files.move(source, dest);
                            if (filePermissions != null) {
                                Files.setPosixFilePermissions(dest, filePermissions);
                            }
                            success = true;
                        } catch (final IOException | RuntimeException e) {
                            LOGGER.debug(e.getMessage(), e);
                        }
                    }
                    attempt++;
                }

                // If we didn't succeed in renaming the file to a failed file
                // then try and delete the file.
                if (!success) {
                    // Try to delete the file, so we can continue to create a
                    // destination.
                    if (LOGGER.isDebugEnabled()) {
                        LOGGER.debug("Deleting file '{}'", getFullPath(file));
                    }
                    if (!Files.deleteIfExists(source)) {
                        LOGGER.error("Failed to delete file '{}'", getFullPath(file));
                    }
                }
            } catch (final IOException | RuntimeException e) {
                LOGGER.debug(e.getMessage(), e);
            }
        }
    }
Optional file permissions to apply to finished files
stroom-pipeline/src/main/java/stroom/pipeline/destination/RollingFileDestination.java