Better error reporting when file deletion fails

- Include file name in all logging
- Log inital attempts at debug to avoid noise
- Include output of 'jps -lm' when final attempt fails
This commit is contained in:
Daz DeBoer 2022-06-06 09:26:49 -06:00
parent 9cd70b5460
commit 8096e65e0a
No known key found for this signature in database
GPG key ID: DD6B9F0B06683D5D
2 changed files with 16 additions and 5 deletions

View file

@ -1,6 +1,8 @@
import * as core from '@actions/core' import * as core from '@actions/core'
import * as cache from '@actions/cache' import * as cache from '@actions/cache'
import * as github from '@actions/github' import * as github from '@actions/github'
import * as exec from '@actions/exec'
import * as crypto from 'crypto' import * as crypto from 'crypto'
import * as path from 'path' import * as path from 'path'
import * as fs from 'fs' import * as fs from 'fs'
@ -195,8 +197,9 @@ export function handleCacheFailure(error: unknown, message: string): void {
* Attempt to delete a file or directory, waiting to allow locks to be released * Attempt to delete a file or directory, waiting to allow locks to be released
*/ */
export async function tryDelete(file: string): Promise<void> { export async function tryDelete(file: string): Promise<void> {
const maxAttempts = 5
const stat = fs.lstatSync(file) const stat = fs.lstatSync(file)
for (let count = 0; count < 3; count++) { for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try { try {
if (stat.isDirectory()) { if (stat.isDirectory()) {
fs.rmdirSync(file, {recursive: true}) fs.rmdirSync(file, {recursive: true})
@ -205,10 +208,13 @@ export async function tryDelete(file: string): Promise<void> {
} }
return return
} catch (error) { } catch (error) {
if (count === 2) { if (attempt === maxAttempts) {
core.warning(`Failed to delete ${file}, which will impact caching.
It is likely locked by another process. Output of 'jps -ml':
${await getJavaProcesses()}`)
throw error throw error
} else { } else {
core.warning(String(error)) cacheDebug(`Attempt to delete ${file} failed. Will try again.`)
await delay(1000) await delay(1000)
} }
} }
@ -218,3 +224,8 @@ export async function tryDelete(file: string): Promise<void> {
async function delay(ms: number): Promise<void> { async function delay(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms)) return new Promise(resolve => setTimeout(resolve, ms))
} }
async function getJavaProcesses(): Promise<string> {
const jpsOutput = await exec.getExecOutput('jps', ['-lm'])
return jpsOutput.stdout
}

View file

@ -13,7 +13,7 @@ const GRADLE_USER_HOME = 'GRADLE_USER_HOME'
const CACHE_LISTENER = 'CACHE_LISTENER' const CACHE_LISTENER = 'CACHE_LISTENER'
const JOB_SUMMARY_ENABLED_PARAMETER = 'generate-job-summary' const JOB_SUMMARY_ENABLED_PARAMETER = 'generate-job-summary'
function generateJobSummary(): boolean { function shouldGenerateJobSummary(): boolean {
return core.getBooleanInput(JOB_SUMMARY_ENABLED_PARAMETER) return core.getBooleanInput(JOB_SUMMARY_ENABLED_PARAMETER)
} }
@ -56,7 +56,7 @@ export async function complete(): Promise<void> {
const gradleUserHome = core.getState(GRADLE_USER_HOME) const gradleUserHome = core.getState(GRADLE_USER_HOME)
await caches.save(gradleUserHome, cacheListener) await caches.save(gradleUserHome, cacheListener)
if (generateJobSummary()) { if (shouldGenerateJobSummary()) {
writeJobSummary(buildResults, cacheListener) writeJobSummary(buildResults, cacheListener)
} }
} }