Using Spring Boot 1.5.1.

The directory /tmp/tomcat-* are not deleted when stopping a Spring Boot application. The directory is created using (in org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory) :

File tempDir = File.createTempFile(prefix + ".", "." + getPort());
            tempDir.delete();
            tempDir.mkdir();
            tempDir.deleteOnExit();
            return tempDir;

I think that deleteOnExit() method doesn't work if the directory is not empty. I made a little standard Java test:

public static void main(String[] args) throws IOException, InterruptedException {
        File tempDir = File.createTempFile("prefix", "suffix");
        tempDir.delete();
        tempDir.mkdir();
        tempDir.deleteOnExit();

        try (FileOutputStream os = new FileOutputStream(new File(tempDir, "noempty.txt"))) {
            os.write("This a not an empty file".getBytes());
        }
        Thread.sleep(Long.MAX_VALUE);
    }

Then I send a linux signal kill -15 <pid> but the folder 'prefix*' is still here.

Comment From: wilkinsona

I think that deleteOnExit() method doesn't work if the directory is not empty

That's correct. We're simply making the best effort we can to clean up the directory when the JVM exits. Sometimes the directory won't be used so we can at least clean up the empty directory on exit. Beyond that, you should configure your OS's standard mechanism for cleaning up tmp when appropriate.

Comment From: gronono

As mentionned on #5009, we cannot always use /tmp as a tomcat's temporary directory.

A JVM shutdown hook could resolve this issue

import org.springframework.util.FileSystemUtils;
...
Runtime.getRuntime().addShutdownHook(new Thread(() -> FileSystemUtils.deleteRecursively(tempDir)));

I can make a Pull Request, if you want.

Comment From: wilkinsona

As far as I know, there's nothing stopping you from using /tmp, you just need to configure the OS to only clean it up when appropriate.

A JVM shutdown hook could resolve this issue

Thanks for the suggestion, but if we always cleared out the whole directory on exit, we'd then get complaints from users who wanted it to remain. For example, users of JSPs may want the directory to remain so that unchanged JSPs don't need to be recompiled.

Comment From: bbossola

It would be really nice to be able to delete such folder if we wanted to: I find this very annoying as I sometimes restart my microservices very frequently, and I'd be perfectly fine with a shutdown hook written in my server code. Is there any way to know where such folder is created, or to provide spring boot with a hint where to create it? Please note that I cannot simply change the value of java.io.tmpdir to my liking, as other libraries are using it as well.

Comment From: snicoll

@bbossola server.tomcat.basedir controls the location. We only create a temp dir if that property isn't specified.

Comment From: bbossola

Thanks, that solves my issue :)

Comment From: jamesSkyDream

Tomcat. file is always generated in the TMP directory after the project is started. How to control how tomcat. file will not be generated in the TMP directory?

Comment From: wilkinsona

@jamesSkyDream That question has been answered by @snicoll two comments above yours: https://github.com/spring-projects/spring-boot/issues/9983#issuecomment-355227395.

Comment From: shollander

@wilkinsona I have found that the shutdown hook created by

https://github.com/spring-projects/spring-boot/blob/b164b16c21734a8581b39553594f102a75bb9738/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/AbstractConfigurableWebServerFactory.java#L176

is never effective since there are other directories that get created underneath that top level directory. I am always left with the following directory tree

/tmp
   \- tomcat.123456789.8080
                          \- work
                                \- Tomcat
                                        \- localhost
                                                   \- ROOT

The directory tree is empty, but will not be cleaned up since the top level tomcat.* directory contains an empty directory. Perhaps a better way to do this would be to create a shutdown hook that would remove the entire directory tree if it does not contain any files.

That being said, I am not sure I understand what you mean by

Thanks for the suggestion, but if we always cleared out the whole directory on exit, we'd then get complaints from users who wanted it to remain. For example, users of JSPs may want the directory to remain so that unchanged JSPs don't need to be recompiled.

The directory created using File.createTempFile() https://github.com/spring-projects/spring-boot/blob/b164b16c21734a8581b39553594f102a75bb9738/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/server/AbstractConfigurableWebServerFactory.java#L173 is guaranteed to be unique and will never be reused after the process exits so it should be safe to force deletion even if the directory does contain files.

Comment From: wilkinsona

is never effective since there are other directories that get created underneath that top level directory

This has already been discussed above

is guaranteed to be unique and will never be reused after the process exits

That's a good point. We could use recursive deletion only in the case where a temporary directory is being used rather than a user-configured directory. That said, I'm not convinced that the extra complexity is worthwhile. The OS already contains a mechanism for cleaning things up.

Comment From: philwebb

We'll have another look at this to see how tricky it might be.

Comment From: wilkinsona

When just deleting an empty directory the ordering of the deletion doesn't matter. If we start deleting the entire directory hierarchy including files that Tomcat has written, the ordering becomes important. That means that we can't use a shutdown hook as the hook that closes the context (and stops Tomcat) and the hook that deletes the directory hierarchy may run in any order or in parallel.

To implement this, I think we'd need to add something to the WebServer implementation that triggers the deletion of the temporary directory hierarchy as part of its stop processing.

Comment From: philwebb

Ergh. I think we should push this back then. It's not too urgent for 2.2.x

Comment From: deepakab03

Thanks, we are facing the same issue where many of these empty folders are created for each test run and not deleted

Comment From: devtech0101

This needs to resolve by an application rather than putting a daily cron to blindly delete everything from /tmp that is related to tomcat. What if you delete the folder that is currently being used by tomcat? will the app function without any issue? why not come up with a clean solution that the spring-boot app can handle unused folder deletion from /tmp on its own?

Comment From: wilkinsona

This needs to resolve by an application

We agree. That's why this issue is open. It's tracking making this improvement to Spring Boot.

rather than putting a daily cron to blindly delete everything from /tmp that is related to tomcat

Irrespective of this issue, /tmp clean up should not do that. Instead, it should only delete files that have not been accessed for a certain amount of time. This is what tmpwatch does, for example.

Comment From: devtech0101

Thanks, @wilkinsona for your reply. Do we have any ticket open for this issue for the Springboot project other than this github issue #9983

Thanks Dev

Comment From: wilkinsona

No. One open issue is sufficient.

Comment From: devtech0101

ok, thanks @wilkinsona any idea on a timeline, when the issue is going to be fixed?

Comment From: wilkinsona

We don’t have any firm plans at the moment and have quite a lot of other, higher priority, things taking our time at the moment. If you or someone else in the community would like to speed things up, a pull request along the lines of what I described above would be welcome. A note of caution, though: from what I remember of when we last looked at this in detail the changes are not straightforward.

Comment From: devtech0101

Ok, thanks @wilkinsona

Comment From: JoshMcCullough

We have 47k of these temp dirs just hangin' out in just one of our environments. I really don't like the idea of writing a cron job to clean these up. Any updates on this?

Comment From: scottfrederick

Any updates on this?

There are no updates to what Andy wrote above.

Comment From: JoshMcCullough

Thank you -- just checking in since that was over a year ago. (Not trying to be pushy.)

Comment From: sam80180

Implement the org.springframework.context.SmartLifecycle interface. In the start() method, use the following code to get the temporary folder path, then remove it in the stop() method:

import org.apache.catalina.Container;
import org.apache.catalina.core.StandardContext;
import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext;
import org.springframework.boot.web.embedded.tomcat.TomcatWebServer;
import org.springframework.context.ApplicationContext;


final ApplicationContext applicationContext = ...;
final ServletWebServerApplicationContext serverContext = (ServletWebServerApplicationContext)applicationContext;
final TomcatWebServer tomcatWebServer = (TomcatWebServer)serverContext.getWebServer();
final Container containers[] = tomcatWebServer.getTomcat().getHost().findChildren();
if (containers==null || containers.length<=0) { return; } // end if
final StandardContext context = (StandardContext)containers[0];
final String relWorkDir = context.getWorkDir();
final String absWorkDir = context.getWorkPath();
final int p = absWorkDir.lastIndexOf(relWorkDir);
if (p>=0) {
    final String tomcatBasedir = absWorkDir.substring(0, p); // <-- here you go
}

Comment From: CharlesLgn

Hello,

I made a PR for this subjet that will resolve the problem without breaking the old behaviour.

By default, the system will dontinue to delete the directory only if it is empty. But if you override the property server.tmp-deletion-strategy, you will be able to delete everything.

Let me know if the PR is legit, or if It needs some updates

Comment From: CharlesLgn

if we use tomcat LifeCycle, we could do something like

one other approche I had imagine was to have in AbstractConfigurableWebServerFactory:

protected final File createTempDir(String prefix) {
    try {
        File tempDir = Files.createTempDirectory(prefix + "." + getPort() + ".").toFile();
        runInShutdown(() -> this.deletionStrategy.deleteOnShutdown(tempDir));
        return tempDir;
    }
    catch (IOException ex) {
        throw new WebServerException(
                "Unable to create tempDir. java.io.tmpdir is set to " + System.getProperty("java.io.tmpdir"), ex);
    }
}

protected void runInShutdown(Runnable shutdownHook) {
    Runtime.getRuntime().addShutdownHook(new Thread(shutdownHook));
}

and in TomcatReactiveWebServerFactory :

@Override
protected void runInShutdown(Runnable shutdownHook) {
    serverLifecycleListeners.add(
        event -> {
            if (event.getType().equals(Lifecycle.AFTER_DESTROY_EVENT) {
                shutdownHook.run();
            }
        }
    );
}

however this solution is great for tomcat, maybe does not awnser the global probleme with Jetty