retry-helper.ts 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061
  1. import * as core from '@actions/core'
  2. const defaultMaxAttempts = 3
  3. const defaultMinSeconds = 10
  4. const defaultMaxSeconds = 20
  5. export class RetryHelper {
  6. private maxAttempts: number
  7. private minSeconds: number
  8. private maxSeconds: number
  9. constructor(
  10. maxAttempts: number = defaultMaxAttempts,
  11. minSeconds: number = defaultMinSeconds,
  12. maxSeconds: number = defaultMaxSeconds
  13. ) {
  14. this.maxAttempts = maxAttempts
  15. this.minSeconds = Math.floor(minSeconds)
  16. this.maxSeconds = Math.floor(maxSeconds)
  17. if (this.minSeconds > this.maxSeconds) {
  18. throw new Error('min seconds should be less than or equal to max seconds')
  19. }
  20. }
  21. async execute<T>(action: () => Promise<T>): Promise<T> {
  22. let attempt = 1
  23. while (attempt < this.maxAttempts) {
  24. // Try
  25. try {
  26. return await action()
  27. } catch (err) {
  28. core.info((err as any)?.message)
  29. }
  30. // Sleep
  31. const seconds = this.getSleepAmount()
  32. core.info(`Waiting ${seconds} seconds before trying again`)
  33. await this.sleep(seconds)
  34. attempt++
  35. }
  36. // Last attempt
  37. return await action()
  38. }
  39. private getSleepAmount(): number {
  40. return (
  41. Math.floor(Math.random() * (this.maxSeconds - this.minSeconds + 1)) +
  42. this.minSeconds
  43. )
  44. }
  45. private async sleep(seconds: number): Promise<void> {
  46. return new Promise(resolve => setTimeout(resolve, seconds * 1000))
  47. }
  48. }
  49. export async function execute<T>(action: () => Promise<T>): Promise<T> {
  50. const retryHelper = new RetryHelper()
  51. return await retryHelper.execute(action)
  52. }