aws-lambda-runner 1.4.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|