From e5843cf5a20ca2a67b3bcb50177a3f9d673bb7ff Mon Sep 17 00:00:00 2001 From: Eryn Lynn Date: Fri, 29 May 2020 02:10:29 -0400 Subject: [PATCH] Add Promise.retry Closes #16 --- lib/README.md | 20 ++++++++++++++++++++ lib/init.lua | 18 ++++++++++++++++++ lib/init.spec.lua | 31 +++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+) diff --git a/lib/README.md b/lib/README.md index 614f39a..d885f5a 100644 --- a/lib/README.md +++ b/lib/README.md @@ -349,6 +349,26 @@ docs: returns: Promise> static: true + - name: retry + desc: | + Repeatedly calls a Promise-returning function up to `times` number of times, until the returned Promise resolves. + + If the amount of retries is exceeded, the function will return the latest rejected Promise. + params: + - name: callback + type: + kind: function + params: "...: P" + returns: Promise + - name: times + type: number + - name: "..." + type: "P" + optional: true + + returns: Promise + static: true + - name: is desc: Checks whether the given object is a Promise via duck typing. This only checks if the object is a table and has an `andThen` method. static: true diff --git a/lib/init.lua b/lib/init.lua index b1f50aa..d3ef75c 100644 --- a/lib/init.lua +++ b/lib/init.lua @@ -1323,4 +1323,22 @@ function Promise.prototype:now(rejectionValue) end end +--[[ + Retries a Promise-returning callback N times until it succeeds. +]] +function Promise.retry(callback, times, ...) + assert(type(callback) == "function", "Parameter #1 to Promise.retry must be a function") + assert(type(times) == "number", "Parameter #2 to Promise.retry must be a number") + + local args, length = {...}, select("#", ...) + + return Promise.resolve(callback(...)):catch(function(...) + if times > 0 then + return Promise.retry(callback, times - 1, unpack(args, 1, length)) + else + return Promise.reject(...) + end + end) +end + return Promise diff --git a/lib/init.spec.lua b/lib/init.spec.lua index 1da168c..9044917 100644 --- a/lib/init.spec.lua +++ b/lib/init.spec.lua @@ -1410,4 +1410,35 @@ return function() expect(innerPromise:getStatus()).to.equal(Promise.Status.Cancelled) end) end) + + describe("Promise.retry", function() + it("should retry N times", function() + local counter = 0 + + local promise = Promise.retry(function(parameter) + expect(parameter).to.equal("foo") + + counter = counter + 1 + + if counter == 5 then + return Promise.resolve("ok") + end + + return Promise.reject("fail") + end, 5, "foo") + + expect(promise:getStatus()).to.equal(Promise.Status.Resolved) + expect(promise._values[1]).to.equal("ok") + end) + + it("should reject if threshold is exceeded", function() + local promise = Promise.retry(function() + return Promise.reject("fail") + end, 5) + + expect(promise:getStatus()).to.equal(Promise.Status.Rejected) + expect(promise._values[1]).to.equal("fail") + end) + end) + end \ No newline at end of file