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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1072f1479b4079a9ad869e54f88e9d7868c5b43b
4
- data.tar.gz: 8385219cdbf104fed5b41b7b44192e78023c0e25
3
+ metadata.gz: fef3ce92ca629b7b66df8d9a5600a690c84c041f
4
+ data.tar.gz: 38d7af195b18d8be62f8ee4591c0cd72ae811744
5
5
  SHA512:
6
- metadata.gz: a36af0663924daa993afb7eac23650e743f7687aa8169a2157959be3866f75e94663a18944da8fd599d8b985d7efb4c709c36abe2b30867d05eda29381a67cd2
7
- data.tar.gz: fa743cd813123c3dc80dee145b0fee65d942a0dec0515c5c063bcd1b0c2978e4deb885a7fe1d7fb8113f6c2e887d67663fcc0cf9eaf74fc3ce99a5ff93bb7897
6
+ metadata.gz: 7c1dab1a066ceaa9608f8041b7e42a1ffa60f7c22ca7a2b6ec504fab3cf36b08bc635bbbfaabaccd7e4a7527d7880c971b42c45c7f5d691a92054e25775d5911
7
+ data.tar.gz: 3a1abbd85b75a90b3307a62c50a4555e85ee3bd452aceb2d17d2e1a4fb0de4264444c7e96167a4dcfcb242efdcc39faee59dc104d4d011f6f297b18e50311bf5
@@ -2,128 +2,170 @@ var merge = require('merge');
2
2
  var url = require('url');
3
3
 
4
4
  var next_id = 0;
5
- // results[id] = { threw: error, completed: [ errorValue, successValue ], timedOut: bool };
6
- var results = {};
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
- exports.request = function(req, res, opts, handler) {
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
- if (req.method === 'POST') {
47
+ var makeContextObject = function (timeout, overrides) {
48
+ var context = merge(true, defaultContextObject(), overrides);
15
49
 
16
- var id = ++next_id;
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
- } else if (req.method === 'DELETE') {
52
+ context.getRemainingTimeInMillis = function () {
53
+ return approximateEndTime - (new Date().getTime());
54
+ };
84
55
 
85
- // FIXME untested
86
- res.writeHead(202, {'Content-Type': 'text/plain'});
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
- } else if (req.method === 'GET') {
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
- var request_id = parseInt(url.parse(req.url, true).query.id);
95
- var result = results[request_id];
85
+ var doCreateJob = function (req, res, opts, handler) {
86
+ var id = ++next_id;
87
+ var job = jobs[id] = new Job();
96
88
 
97
- var status = null;
98
- var responseBody = null;
89
+ var requestBody = '';
99
90
 
100
- if (result === undefined) {
101
- status = 404;
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
- if (result.completed) {
104
- if (result.completed[0] !== null && result.completed[0] !== undefined) {
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
- // non-standard stringification of undefined
123
- if (responseBody === undefined) responseBody = null;
139
+ exports.request = function(req, res, opts, handler) {
124
140
 
125
- res.writeHead(status, {'Content-Type': 'application/json'});
126
- res.end(JSON.stringify(responseBody) + '\n');
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 :
@@ -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.to_json
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.to_json
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
@@ -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
- json = LambdaRunner::Events.s3_event("some-bucket", "some/key", "local/path")
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
- json = LambdaRunner::Events.sns_event("some-arn", "some-id", "some-timestamp", "some-body")
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.0
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
- - lib/sample_cloudwatch_event.json
152
- - lib/sample_s3_event.json
153
- - lib/sample_s3_test_event.json
154
- - lib/sample_scheduled_event.json
155
- - lib/sample_sns_event.json
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: