Skip to content

Commit

Permalink
fix: resolve issues with multiple targets and func versions (#60)
Browse files Browse the repository at this point in the history
  • Loading branch information
naorpeled authored Nov 25, 2023
1 parent 528d9c0 commit fa63b76
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 40 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ dump.rdb
# Coverage reports
.nyc_output
coverage
.idea
14 changes: 7 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,16 @@ const funcVersion = process.env.AWS_LAMBDA_FUNCTION_VERSION
const delay = ms => new Promise(res => setTimeout(res, ms))

const handleEvent = (event, config) => {
// If the event is a warmer ping
if (event && event[config.flag]) {
const isWarmerPing = event && event[config.flag]
if (isWarmerPing) {
let concurrency =
event[config.concurrency] &&
!isNaN(event[config.concurrency]) &&
event[config.concurrency] > 1
? event[config.concurrency]
: 1

// Default target to funcName
let target = event[config.target] || funcName
let target = event[config.target] || `${funcName}:${funcVersion}`

let invokeCount =
event['__WARMER_INVOCATION__'] && !isNaN(event['__WARMER_INVOCATION__'])
Expand All @@ -49,7 +48,7 @@ const handleEvent = (event, config) => {
// Create log record
let log = {
action: 'warmer',
function: funcName + ':' + funcVersion,
function: `${funcName}:${funcVersion}`,
id,
correlationId,
count: invokeCount,
Expand All @@ -69,8 +68,9 @@ const handleEvent = (event, config) => {
warm = true
lastAccess = Date.now()

// Check wether this lambda is invoking a different lambda
let isDifferentTarget = target !== funcName
// Check whether this lambda is invoking a different lambda
let isDifferentTarget = !(target === `${funcName}:${funcVersion}` ||
(target === funcName && funcVersion === '$LATEST'))

// Fan out if concurrency is set higher than 1
if ((concurrency > 1 || isDifferentTarget) && !event[config.test]) {
Expand Down
15 changes: 15 additions & 0 deletions test/multiple-events.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const lambda = require('../lib/lambda-service') // Init Lambda Service

// Seed expected environment variable
process.env.AWS_LAMBDA_FUNCTION_NAME = 'test-function'
process.env.AWS_LAMBDA_FUNCTION_VERSION = '$LATEST'

let stub // init stub

Expand All @@ -22,6 +23,20 @@ describe('Target Tests', function() {
})

describe('Using default configuration', function() {
it('should do nothing if received an array of events that only contains the same lambda with concurrency of 1', function(done) {
let warmer = rewire('../index')
stub.returns(true)

let event = [
{ warmer: true, concurrency: 1, target: 'test-function' }
]
warmer(event, { log: false }).then(out => {
expect(stub.callCount).to.equal(0)
expect(out).to.equal(true)
done()
})
})

it('should invoke multiple lambdas', function(done) {
let warmer = rewire('../index')
stub.returns(true)
Expand Down
138 changes: 105 additions & 33 deletions test/target.js
Original file line number Diff line number Diff line change
@@ -1,49 +1,122 @@
'use strict';
'use strict'

const expect = require('chai').expect // assertion library
const sinon = require('sinon') // Require Sinon.js library
const rewire = require('rewire') // Rewire library

const lambda = require('../lib/lambda-service') // Init Lambda Service

// Seed expected environment variable
process.env.AWS_LAMBDA_FUNCTION_NAME = 'test-function'
let stub

let stub // init stub
describe('Target Tests', function () {

describe('Target Tests', function() {
beforeEach(function () {
stub = sinon.stub(lambda, 'invoke')

beforeEach(function() {
// Stub invoke
stub = sinon.stub(lambda,'invoke')
process.env.AWS_LAMBDA_FUNCTION_NAME = 'test-function'
process.env.AWS_LAMBDA_FUNCTION_VERSION = '$LATEST'
})

afterEach(function() {
afterEach(function () {
stub.restore()
})

describe('Using default configuration', function() {
describe('Using default configuration', function () {

it('should invoke the lambda', function(done) {
it('should do nothing if there is no target in the event and the concurrency is 1 and function version is $LATEST', function (done) {
let warmer = rewire('../index')
stub.returns(true)

let event = { warmer: true, concurrency: 1, target: 'other' }
warmer(event, { log:false }).then(out => {
expect(stub.callCount).to.equal(1)
expect(stub.args[0][0].InvocationType).to.equal('RequestResponse')
expect(stub.args[0][0].FunctionName).to.equal('other')
let event = { warmer: true, concurrency: 1 }
warmer(event, { log: false }).then(out => {
expect(stub.callCount).to.equal(0)
expect(out).to.equal(true)
done()
})
})

it('should do nothing if there is no target in the event and the concurrency is 1 and function version is not $LATEST', function (done) {
process.env.AWS_LAMBDA_FUNCTION_VERSION = '1'

let warmer = rewire('../index')
stub.returns(true)

let event = { warmer: true, concurrency: 1 }
warmer(event, { log: false }).then(out => {
expect(stub.callCount).to.equal(0)
expect(out).to.equal(true)
done()
})
})

it('should return true with two lambda invocations', function(done) {
it(
'should invoke the same lambda if there is no target in the event and the concurrency is more than 1',
function (done) {
let warmer = rewire('../index')
stub.returns(true)

let event = { warmer: true, concurrency: 2 }
warmer(event, { log: false }).then(out => {
expect(stub.callCount).to.equal(1)
expect(stub.args[0][0].InvocationType).to.equal('RequestResponse')
expect(stub.args[0][0].FunctionName).to.equal('test-function:$LATEST')
expect(out).to.equal(true)
done()
})
},
)

describe('should invoke a different lambda', function (done) {
it('if the target function name is different', function (done) {
let warmer = rewire('../index')
stub.returns(true)

let event = { warmer: true, concurrency: 1, target: 'other' }
warmer(event, { log: false }).then(out => {
expect(stub.callCount).to.equal(1)
expect(stub.args[0][0].InvocationType).to.equal('RequestResponse')
expect(stub.args[0][0].FunctionName).to.equal('other')
expect(out).to.equal(true)
done()
})
})

it('if the target function version is different', function (done) {
let warmer = rewire('../index')
stub.returns(true)

let event = { warmer: true, concurrency: 1, target: 'test-function:1' }
warmer(event, { log: false }).then(out => {
expect(stub.callCount).to.equal(1)
expect(stub.args[0][0].InvocationType).to.equal('RequestResponse')
expect(stub.args[0][0].FunctionName).to.equal('test-function:1')
expect(out).to.equal(true)
done()
})
})

it('if the current function is not $LATEST and the target is with no alias (i.e. $LATEST)', function (done) {
process.env.AWS_LAMBDA_FUNCTION_VERSION = '1'
let warmer = rewire('../index')
stub.returns(true)

let event = { warmer: true, concurrency: 1, target: 'test-function' }
warmer(event, { log: false }).then(out => {
expect(stub.callCount).to.equal(1)
expect(stub.args[0][0].InvocationType).to.equal('RequestResponse')
expect(stub.args[0][0].FunctionName).to.equal('test-function')
expect(out).to.equal(true)
done()
})
})
})

it('should return true with two lambda invocations', function (done) {
let warmer = rewire('../index')
stub.returns(true)

let event = { warmer: true, concurrency: 2, target: 'other' }
warmer(event, { log:false }).then(out => {
warmer(event, { log: false }).then(out => {
expect(stub.callCount).to.equal(2)
expect(stub.args[0][0].InvocationType).to.equal('Event')
expect(stub.args[0][0].FunctionName).to.equal('other')
Expand All @@ -54,12 +127,12 @@ describe('Target Tests', function() {
})
})

it('should return true with three lambda invocations', function(done) {
it('should return true with three lambda invocations', function (done) {
let warmer = rewire('../index')
stub.returns(true)

let event = { warmer: true, concurrency: 3, target: 'other' }
warmer(event, { log:false }).then(out => {
warmer(event, { log: false }).then(out => {
expect(stub.callCount).to.equal(3)
expect(stub.args[0][0].InvocationType).to.equal('Event')
expect(stub.args[0][0].FunctionName).to.equal('other')
Expand All @@ -74,14 +147,14 @@ describe('Target Tests', function() {

})

describe('Using modified configuration', function() {
describe('Using modified configuration', function () {

it('should return true with a single lambda invocation', function(done) {
it('should return true with a single lambda invocation', function (done) {
let warmer = rewire('../index')
stub.returns(true)

let event = { warmerX: true, concurrencyX: 1, targetX: 'other' }
warmer(event, { flag: 'warmerX', concurrency: 'concurrencyX', target: 'targetX', log:false }).then(out => {
warmer(event, { flag: 'warmerX', concurrency: 'concurrencyX', target: 'targetX', log: false }).then(out => {
expect(stub.callCount).to.equal(1)
expect(stub.args[0][0].InvocationType).to.equal('RequestResponse')
expect(stub.args[0][0].FunctionName).to.equal('other')
Expand All @@ -90,12 +163,12 @@ describe('Target Tests', function() {
})
})

it('should return true with two lambda invocations', function(done) {
it('should return true with two lambda invocations', function (done) {
let warmer = rewire('../index')
stub.returns(true)

let event = { warmerX: true, concurrencyX: 2, targetX: 'other' }
warmer(event, { flag: 'warmerX', concurrency: 'concurrencyX', target: 'targetX', log:false }).then(out => {
warmer(event, { flag: 'warmerX', concurrency: 'concurrencyX', target: 'targetX', log: false }).then(out => {
expect(stub.callCount).to.equal(2)
expect(stub.args[0][0].InvocationType).to.equal('Event')
expect(stub.args[0][0].FunctionName).to.equal('other')
Expand All @@ -106,12 +179,12 @@ describe('Target Tests', function() {
})
})

it('should return true with three lambda invocations', function(done) {
it('should return true with three lambda invocations', function (done) {
let warmer = rewire('../index')
stub.returns(true)

let event = { warmerX: true, concurrencyX: 3, targetX: 'other' }
warmer(event, { flag: 'warmerX', concurrency: 'concurrencyX', target: 'targetX', log:false }).then(out => {
warmer(event, { flag: 'warmerX', concurrency: 'concurrencyX', target: 'targetX', log: false }).then(out => {
expect(stub.callCount).to.equal(3)
expect(stub.args[0][0].InvocationType).to.equal('Event')
expect(stub.args[0][0].FunctionName).to.equal('other')
Expand All @@ -126,18 +199,17 @@ describe('Target Tests', function() {

})

describe('Lambda Invocation Errors', function () {

describe('Lambda Invocation Errors', function() {

it('should throw an error', function() {
it('should throw an error', function () {
let warmer = rewire('../index')
stub.throws(new Error('some error'))
let event = { warmer: true, concurrency: 2, target: 'other' }
let error

try{
warmer(event, { log:false })
} catch(e) {
try {
warmer(event, { log: false })
} catch (e) {
error = e
}

Expand Down

0 comments on commit fa63b76

Please sign in to comment.