When running a Jenkins server with many jobs and many agents, you can quickly run out of disk space because of orphan workspaces:

  • Jobs may roam on different agents, leaving a workspace on each
  • Each concurrent job execution needs its own workspace
  • When renaming or deleting a job, the workspaces may still survive on the disk (with the original job name)

With the Workspace Cleanup Plugin, the workspace may be deleted after a job execution (as post-build action), but this has other drawbacks:

  • Every job execution needs a full SCM checkout (instead of an update), which can be very time-consuming
  • If something goes wrong, there is no workspace for a post-mortem analysis

My solution is a simple Groovy script that iterates through all workspace directories on all agents, and deletes a workspace if it is older than one day:

def deleted = []
def oneDayAgo = new Date() - 1
jenkins.model.Jenkins.instance.nodes.each { hudson.model.Node node ->
  node.workspaceRoot.listDirectories().each { hudson.FilePath path ->
    def pathName = path.getRemote()
    if (path.name.startsWith(".")) {
      println "Skipping internal dir $node.displayName:$pathName"
    } else {
	    def lastModified = new Date(path.lastModified())
      if (lastModified < oneDayAgo) {
        println "Deleting workspace at $node.displayName:$pathName (last modified $lastModified)"
        path.deleteRecursive()
        deleted << "$node.displayName:$pathName"
      } else {
        println "Skipping workspace at $node.displayName:$pathName (last modified $lastModified)"
      }
    }
  }
}
"Deleted workspaces: \n\t" + deleted.sort().join("\n\t")

Of course this assumes that all jobs use the default workspace location.

This can either be executed with the Jenkins Script Console or as part of a scheduled maintenance job, using a System Groovy Script.

comments powered by Disqus