aws-lambda-runner 1.4.0 → 1.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/js/request.js +149 -105
- data/lib/lambda_runner.rb +10 -6
- data/{lib → samples}/sample_cloudwatch_event.json +0 -0
- data/{lib → samples}/sample_s3_event.json +0 -0
- data/{lib → samples}/sample_s3_test_event.json +0 -0
- data/{lib → samples}/sample_scheduled_event.json +0 -0
- data/{lib → samples}/sample_sns_event.json +0 -0
- data/spec/lambda-runner_spec.rb +2 -4
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fef3ce92ca629b7b66df8d9a5600a690c84c041f
|
4
|
+
data.tar.gz: 38d7af195b18d8be62f8ee4591c0cd72ae811744
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c1dab1a066ceaa9608f8041b7e42a1ffa60f7c22ca7a2b6ec504fab3cf36b08bc635bbbfaabaccd7e4a7527d7880c971b42c45c7f5d691a92054e25775d5911
|
7
|
+
data.tar.gz: 3a1abbd85b75a90b3307a62c50a4555e85ee3bd452aceb2d17d2e1a4fb0de4264444c7e96167a4dcfcb242efdcc39faee59dc104d4d011f6f297b18e50311bf5
|
data/js/request.js
CHANGED
@@ -2,128 +2,170 @@ var merge = require('merge');
|
|
2
2
|
var url = require('url');
|
3
3
|
|
4
4
|
var next_id = 0;
|
5
|
-
//
|
6
|
-
|
5
|
+
// FIXME: this object grows forever - entries are never removed. Should they
|
6
|
+
// be removed by expiry (time), and/or a REST API call?
|
7
|
+
var jobs = {};
|
8
|
+
|
9
|
+
var Job = function () {
|
10
|
+
};
|
11
|
+
|
12
|
+
Job.prototype.doError = function (error) {
|
13
|
+
if (!this.completionValues && !this.timedOut) {
|
14
|
+
this.threw = error;
|
15
|
+
}
|
16
|
+
};
|
17
|
+
|
18
|
+
Job.prototype.doCompletion = function (errorValue, successValue) {
|
19
|
+
if (!this.threw && !this.timedOut) {
|
20
|
+
this.completionValues = [ errorValue, successValue ];
|
21
|
+
}
|
22
|
+
};
|
23
|
+
|
24
|
+
Job.prototype.doTimedOut = function () {
|
25
|
+
if (!this.threw && !this.completionValues) {
|
26
|
+
this.timedOut = true;
|
27
|
+
}
|
28
|
+
};
|
7
29
|
|
8
30
|
var region = function () {
|
9
31
|
return process.env.AWS_DEFAULT_REGION || process.env.AWS_REGION || process.env.AMAZON_REGION || "xx-dummy-0";
|
10
32
|
};
|
11
33
|
|
12
|
-
|
34
|
+
var defaultContextObject = function () {
|
35
|
+
return {
|
36
|
+
// Fixed, but reasonably representative
|
37
|
+
functionName: "via-aws-lambda-runner",
|
38
|
+
functionVersion: "$LATEST",
|
39
|
+
invokedFunctionArn: "arn:aws:lambda:" + region() + ":000000000000:function:via-aws-lambda-runner:$LATEST",
|
40
|
+
memoryLimitInMB: 100,
|
41
|
+
awsRequestId: "00000000-0000-0000-0000-000000000000",
|
42
|
+
logGroupName: "/aws/lambda/via-aws-lambda-runner",
|
43
|
+
logStreamName: "some-log-stream-name",
|
44
|
+
};
|
45
|
+
};
|
13
46
|
|
14
|
-
|
47
|
+
var makeContextObject = function (timeout, overrides) {
|
48
|
+
var context = merge(true, defaultContextObject(), overrides);
|
15
49
|
|
16
|
-
|
17
|
-
results[id] = {};
|
18
|
-
|
19
|
-
var requestBody = '';
|
20
|
-
|
21
|
-
req.on('data', function(chunk) {
|
22
|
-
requestBody += chunk.toString();
|
23
|
-
});
|
24
|
-
|
25
|
-
req.on('end', function(chunk) {
|
26
|
-
setTimeout(function() {
|
27
|
-
if (!results[id].completed) {
|
28
|
-
results[id].timedOut = true;
|
29
|
-
}
|
30
|
-
}, opts.timeout);
|
31
|
-
|
32
|
-
var requestObject;
|
33
|
-
try {
|
34
|
-
requestObject = JSON.parse(requestBody);
|
35
|
-
} catch (e) {
|
36
|
-
console.log("POSTed bad json: " + e.toString());
|
37
|
-
res.writeHead(400, {'Content-Type': 'text/plain'});
|
38
|
-
res.end(e.toString());
|
39
|
-
return;
|
40
|
-
}
|
41
|
-
|
42
|
-
res.writeHead(200, {'Content-Type': 'text/plain'});
|
43
|
-
res.end(String(id));
|
44
|
-
|
45
|
-
var approximateEndTime = (new Date().getTime()) + opts.timeout;
|
46
|
-
|
47
|
-
var context = {
|
48
|
-
done: function(err, message) {
|
49
|
-
results[id].completed = [ err, message ];
|
50
|
-
if (err) {
|
51
|
-
console.warn('Error:', err);
|
52
|
-
}
|
53
|
-
},
|
54
|
-
getRemainingTimeInMillis: function () {
|
55
|
-
return approximateEndTime - (new Date().getTime());
|
56
|
-
},
|
57
|
-
|
58
|
-
// Fixed, but reasonably representative
|
59
|
-
functionName: "via-aws-lambda-runner",
|
60
|
-
functionVersion: "$LATEST",
|
61
|
-
invokedFunctionArn: "arn:aws:lambda:" + region() + ":000000000000:function:via-aws-lambda-runner:$LATEST",
|
62
|
-
memoryLimitInMB: 100,
|
63
|
-
awsRequestId: "00000000-0000-0000-0000-000000000000",
|
64
|
-
logGroupName: "/aws/lambda/via-aws-lambda-runner",
|
65
|
-
logStreamName: "some-log-stream-name",
|
66
|
-
};
|
67
|
-
|
68
|
-
context.fail = function(err) { context.done(err, null); };
|
69
|
-
context.succeed = function(data) { context.done(null, data); };
|
70
|
-
|
71
|
-
var event = requestObject.event;
|
72
|
-
merge(context, requestObject.context || {});
|
73
|
-
|
74
|
-
try {
|
75
|
-
handler(event, context);
|
76
|
-
} catch (e) {
|
77
|
-
console.log("Handler crashed", e);
|
78
|
-
results[id].threw = e;
|
79
|
-
}
|
80
|
-
|
81
|
-
});
|
50
|
+
var approximateEndTime = (new Date().getTime()) + timeout;
|
82
51
|
|
83
|
-
|
52
|
+
context.getRemainingTimeInMillis = function () {
|
53
|
+
return approximateEndTime - (new Date().getTime());
|
54
|
+
};
|
84
55
|
|
85
|
-
|
86
|
-
|
87
|
-
var terminationMessage = 'Terminating server at http://[localhost]:' + opts.port + ' for ' + opts['module-path'] + ' / ' + opts.handler;
|
88
|
-
res.end(terminationMessage + '\n');
|
89
|
-
console.info(terminationMessage);
|
90
|
-
server.close();
|
56
|
+
context.fail = function(err) { context.done(err, null); };
|
57
|
+
context.succeed = function(data) { context.done(null, data); };
|
91
58
|
|
92
|
-
|
59
|
+
return context;
|
60
|
+
};
|
61
|
+
|
62
|
+
var startJob = function (job, requestObject, handler, opts) {
|
63
|
+
setTimeout(function() {
|
64
|
+
job.doTimedOut();
|
65
|
+
}, opts.timeout);
|
66
|
+
|
67
|
+
var event = requestObject.event;
|
68
|
+
|
69
|
+
var context = makeContextObject(opts.timeout, requestObject.context || {});
|
70
|
+
context.done = function (err, result) {
|
71
|
+
job.doCompletion(err, result);
|
72
|
+
if (err) {
|
73
|
+
console.warn('Error:', err);
|
74
|
+
}
|
75
|
+
};
|
76
|
+
|
77
|
+
try {
|
78
|
+
handler(event, context);
|
79
|
+
} catch (e) {
|
80
|
+
console.log("Handler crashed", e);
|
81
|
+
job.doError(e);
|
82
|
+
}
|
83
|
+
};
|
93
84
|
|
94
|
-
|
95
|
-
|
85
|
+
var doCreateJob = function (req, res, opts, handler) {
|
86
|
+
var id = ++next_id;
|
87
|
+
var job = jobs[id] = new Job();
|
96
88
|
|
97
|
-
|
98
|
-
var responseBody = null;
|
89
|
+
var requestBody = '';
|
99
90
|
|
100
|
-
|
101
|
-
|
91
|
+
req.on('data', function(chunk) {
|
92
|
+
requestBody += chunk.toString();
|
93
|
+
});
|
94
|
+
|
95
|
+
req.on('end', function() {
|
96
|
+
var requestObject;
|
97
|
+
|
98
|
+
try {
|
99
|
+
requestObject = JSON.parse(requestBody);
|
100
|
+
} catch (e) {
|
101
|
+
console.log("POSTed bad json: " + e.toString());
|
102
|
+
res.writeHead(400, {'Content-Type': 'text/plain'});
|
103
|
+
res.end(e.toString());
|
104
|
+
return;
|
105
|
+
}
|
106
|
+
|
107
|
+
res.writeHead(200, {'Content-Type': 'text/plain'});
|
108
|
+
res.end(String(id));
|
109
|
+
|
110
|
+
startJob(job, requestObject, handler, opts);
|
111
|
+
});
|
112
|
+
};
|
113
|
+
|
114
|
+
var getJobStatus = function (result) {
|
115
|
+
var status = null;
|
116
|
+
var responseBody = null;
|
117
|
+
|
118
|
+
if (result.completionValues) {
|
119
|
+
if (result.completionValues[0] !== null && result.completionValues[0] !== undefined) {
|
120
|
+
status = 502;
|
121
|
+
responseBody = result.completionValues[0];
|
102
122
|
} else {
|
103
|
-
|
104
|
-
|
105
|
-
status = 502;
|
106
|
-
responseBody = result.completed[0];
|
107
|
-
} else {
|
108
|
-
status = 201;
|
109
|
-
responseBody = result.completed[1];
|
110
|
-
}
|
111
|
-
} else if (result.threw) {
|
112
|
-
status = 500;
|
113
|
-
responseBody = result.threw.toString();
|
114
|
-
} else if (result.timedOut) {
|
115
|
-
status = 504;
|
116
|
-
} else {
|
117
|
-
// still in progress
|
118
|
-
status = 200;
|
119
|
-
}
|
123
|
+
status = 201;
|
124
|
+
responseBody = result.completionValues[1];
|
120
125
|
}
|
126
|
+
} else if (result.threw) {
|
127
|
+
status = 500;
|
128
|
+
responseBody = result.threw.toString();
|
129
|
+
} else if (result.timedOut) {
|
130
|
+
status = 504;
|
131
|
+
} else {
|
132
|
+
// still in progress
|
133
|
+
status = 200;
|
134
|
+
}
|
135
|
+
|
136
|
+
return { status: status, data: responseBody };
|
137
|
+
};
|
121
138
|
|
122
|
-
|
123
|
-
if (responseBody === undefined) responseBody = null;
|
139
|
+
exports.request = function(req, res, opts, handler) {
|
124
140
|
|
125
|
-
|
126
|
-
|
141
|
+
if (req.method === 'POST') {
|
142
|
+
|
143
|
+
doCreateJob(req, res, opts, handler);
|
144
|
+
|
145
|
+
} else if (req.method === 'DELETE') {
|
146
|
+
|
147
|
+
(function () {
|
148
|
+
// FIXME untested
|
149
|
+
res.writeHead(202, {'Content-Type': 'text/plain'});
|
150
|
+
var terminationMessage = 'Terminating server at http://[localhost]:' + opts.port + ' for ' + opts['module-path'] + ' / ' + opts.handler;
|
151
|
+
res.end(terminationMessage + '\n');
|
152
|
+
console.info(terminationMessage);
|
153
|
+
server.close();
|
154
|
+
})();
|
155
|
+
|
156
|
+
} else if (req.method === 'GET') {
|
157
|
+
|
158
|
+
(function () {
|
159
|
+
var request_id = parseInt(url.parse(req.url, true).query.id);
|
160
|
+
var result = jobs[request_id];
|
161
|
+
var answer = result ? getJobStatus(result) : { status: 404, data: null };
|
162
|
+
|
163
|
+
// non-standard stringification of undefined
|
164
|
+
if (answer.data === undefined) answer.data = null;
|
165
|
+
|
166
|
+
res.writeHead(answer.status, {'Content-Type': 'application/json'});
|
167
|
+
res.end(JSON.stringify(answer.data) + '\n');
|
168
|
+
})();
|
127
169
|
|
128
170
|
} else {
|
129
171
|
|
@@ -133,3 +175,5 @@ exports.request = function(req, res, opts, handler) {
|
|
133
175
|
}
|
134
176
|
|
135
177
|
};
|
178
|
+
|
179
|
+
// vi: set sw=2 et :
|
data/lib/lambda_runner.rb
CHANGED
@@ -4,10 +4,6 @@ require 'json'
|
|
4
4
|
require 'English'
|
5
5
|
require 'fileutils'
|
6
6
|
|
7
|
-
def load_json(name)
|
8
|
-
File.open(File.join(File.dirname(__FILE__), name)) { |file| return JSON.load(file) }
|
9
|
-
end
|
10
|
-
|
11
7
|
# runs a nodejs lambda program so the s3 events can be sent to it via http post
|
12
8
|
module LambdaRunner
|
13
9
|
# abstract for running the program
|
@@ -84,7 +80,7 @@ module LambdaRunner
|
|
84
80
|
record['s3']['object']['key'] = key
|
85
81
|
record
|
86
82
|
end
|
87
|
-
event
|
83
|
+
event
|
88
84
|
end
|
89
85
|
|
90
86
|
def self.sns_event(topicArn, messageId, timestamp, messageBody)
|
@@ -95,8 +91,16 @@ module LambdaRunner
|
|
95
91
|
record['Sns']['Timestamp'] = timestamp
|
96
92
|
record['Sns']['Message'] = messageBody
|
97
93
|
end
|
98
|
-
event
|
94
|
+
event
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def self.load_json(name)
|
100
|
+
base = File.dirname(File.dirname(__FILE__))
|
101
|
+
File.open(File.join(base, "samples", name)) { |file| return JSON.load(file) }
|
99
102
|
end
|
103
|
+
|
100
104
|
end
|
101
105
|
end
|
102
106
|
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
data/spec/lambda-runner_spec.rb
CHANGED
@@ -4,8 +4,7 @@ require_relative '../lib/lambda_runner'
|
|
4
4
|
describe LambdaRunner::Events do
|
5
5
|
|
6
6
|
it "should generate an S3 event" do
|
7
|
-
|
8
|
-
data = JSON.parse json
|
7
|
+
data = LambdaRunner::Events.s3_event("some-bucket", "some/key", "local/path")
|
9
8
|
expect(data["Records"][0]["file"]["path"]).to eq("local/path")
|
10
9
|
expect(data["Records"][0]["s3"]["bucket"]["name"]).to eq("some-bucket")
|
11
10
|
expect(data["Records"][0]["s3"]["bucket"]["arn"]).to eq("arn:aws:s3:::some-bucket")
|
@@ -13,8 +12,7 @@ describe LambdaRunner::Events do
|
|
13
12
|
end
|
14
13
|
|
15
14
|
it "should generate an SNS event" do
|
16
|
-
|
17
|
-
data = JSON.parse json
|
15
|
+
data = LambdaRunner::Events.sns_event("some-arn", "some-id", "some-timestamp", "some-body")
|
18
16
|
expect(data["Records"][0]["Sns"]["TopicArn"]).to eq("some-arn")
|
19
17
|
expect(data["Records"][0]["Sns"]["MessageId"]).to eq("some-id")
|
20
18
|
expect(data["Records"][0]["Sns"]["Timestamp"]).to eq("some-timestamp")
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-lambda-runner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- andrew wheat
|
8
8
|
- tristan hill
|
9
9
|
- stuart hicks
|
10
|
+
- rachel evans
|
10
11
|
autorequire:
|
11
12
|
bindir: bin
|
12
13
|
cert_chain: []
|
@@ -148,11 +149,11 @@ files:
|
|
148
149
|
- js/request.js
|
149
150
|
- js/startup.js
|
150
151
|
- lib/lambda_runner.rb
|
151
|
-
-
|
152
|
-
-
|
153
|
-
-
|
154
|
-
-
|
155
|
-
-
|
152
|
+
- samples/sample_cloudwatch_event.json
|
153
|
+
- samples/sample_s3_event.json
|
154
|
+
- samples/sample_s3_test_event.json
|
155
|
+
- samples/sample_scheduled_event.json
|
156
|
+
- samples/sample_sns_event.json
|
156
157
|
- spec/lambda-runner_spec.rb
|
157
158
|
homepage: https://github.com/bbc/aws-lambda-runner
|
158
159
|
licenses:
|