2016-05-19 6 views
11

zu Feuerbasis ich Feuerbasis ‚‚Modul nicht gefunden‘, wenn ich versuche, dies in Lambda (Node.js 4,3)Amazon Lambda

var Firebase = require('firebase'); 

gleiche passiert, wenn ich ein ZIP-Paket zu laden versuchen zu laufen, die folgenden beinhaltet node_modules/firebase

Hat jemand eine funktionierende 'Write from Lambda to Firebase' Implementierung? anstelle der Inhalt des Projektordners

Ordner Projekt Zipping:

Antwort

9

löste ich mein Problem durch Feuerbasis REST api

var https = require('https'); 

exports.handler = function(event, context, callback) { 

    var body = JSON.stringify({ 
     foo: "bar" 
    }) 

    var https = require('https'); 

var options = { 
    host: 'project-XXXXX.firebaseio.com', 
    port: 443, 
    path: '/.json', 
    method: 'POST' 
}; 

var req = https.request(options, function(res) { 
    console.log(res.statusCode); 
    res.on('data', function(d) { 
    process.stdout.write(d); 
    }); 
}); 
req.end(body); 

req.on('error', function(e) { 
    console.error(e); 
}); 

    callback(null, "some success message"); 

} 
8

Dies ist spät mit, aber im Falle jemand anderes sucht kann dies verursachen. Der gezippte Ordner sollte nach dem Extrahieren keinen Ordner mit den Lambda-Dateien enthalten, sondern sollte die Datei index.js und den Ordner node_modules auf der Stammebene enthalten.

Ein Arbeitsbeispiel einer Lambda-Funktion (mit neuesten glänzenden Feuerbasis Sachen * seufz *):

var firebase = require('firebase'); 

// Your service account details 
var credentials = { 
    "type": "service_account", 
    "project_id": "project-123451234512345123", 
    "private_key_id": "my1private2key3id", 
    "private_key": "-----BEGIN PRIVATE KEY-----InsertKeyHere-----END PRIVATE KEY-----\n", 
    "client_email": "[email protected]", 
    "client_id": "1111222223333344444", 
    "auth_uri": "https://accounts.google.com/o/oauth2/auth", 
    "token_uri": "https://accounts.google.com/o/oauth2/token", 
    "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", 
    "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/projectname%40project-123451234512345123.iam.gserviceaccount.com" 
}; 

firebase.initializeApp({ 
    serviceAccount: credentials, 
    databaseURL: "https://project-123451234512345123.firebaseio.com" 
}); 

exports.handler = function (event, context, callback) { 

    // I use some data passed in from AWS API Gateway: 
    if (!event.firebaseUid) { 
    callback('Missing param for id'); 
    } 

    firebase.database().ref().child('users').child(firebaseUid).child('at').set(newTokens.access_token).then(function (data) { 
    console.log('Firebase data: ', data); 
    firebase.database().goOffline(); 
    callback(null, 'Firebase data: ', data); 
    }).catch(function (error) { 
    callback('Database set error ' + error); 
    }); 
}; 

Jetzt für die Einschränkung. Ich habe erlebt, dass die Lambda-Funktion einen Timeout hat, selbst nachdem der Firebase-Callback stattgefunden hat, d. Die Set-Funktion scheint einen Listener zu erzeugen, der die Lambda-Funktion trotz Rückgabe korrekter Daten offen hält.

Update: Aufruf von firebase.database(). GoOffline() behebt das Lambda-Funktion-Timeout-Problem, das aufgetreten ist.

Die üblichen Vorsichtsmaßregeln bezüglich der Sicherheit, die nicht verifiziert werden oder angemessen sind, und die Möglichkeiten des Anhaltens von Raum und Zeit, indem Sie dies anwenden.

+0

ich bin im Moment auf meinem lokalen Rechner arbeiten (in Java-Skript), aber meine Funktion hat sich auch am Ende festgefahren. goOffline() funktioniert in meinem Fall nicht. Wie hast du das repariert? –

+0

Ich arbeite gerade an meinem lokalen Rechner (in Java Script), aber meine Funktion hat sich auch am Ende festgefahren. goOffline() funktioniert in meinem Fall nicht. Wie hast du das repariert? –

+1

@ josiah-chois Antwort unten löste das Problem für mich - siehe 'context.callbackWaitsForEmptyEventLoop = false' – dsl101

16

sicher Feuerbasis npm Paket (Version 3.3.0) in AWS Lambda (NodeJS 4.3) zu verwenden, gehen Sie wie folgt vor:

'use strict'; 

var firebase = require("firebase"); 

exports.handler = (event, context, callback) => { 
    context.callbackWaitsForEmptyEventLoop = false; //<---Important 

    var config = { 
     apiKey: "<<apikey>>", 
     authDomain: "<<app_id>>.firebaseapp.com", 
     databaseURL: "https://<<app_id>>.firebaseio.com", 
     storageBucket: "<<app_id>>.appspot.com", 
    }; 

    if(firebase.apps.length == 0) { // <---Important!!! In lambda, it will cause double initialization. 
     firebase.initializeApp(config); 
    } 

    ... 
    <Your Logic here...> 
    ... 
}; 
+0

Dies hat ein Problem gelöst, mit dem ich gerungen habe. Wie um alles in der Welt hast du diese 2 Edelsteine ​​gefunden, um den Firebase arbeiten zu lassen? Und ich verstehe immer noch nicht wirklich die zweite ('fireabase.apps.length == 0') - laut meinen Logs ist es immer nur 0, aber wenn ich diesen Test nicht mache, läuft die Zeit ab. Also ich weiß, dass ich es tun muss, aber ich möchte wirklich wissen, warum. – dsl101

+0

OK - einige Spekulationen (ich bin neu bei Lambda): 'context.callbackWaitsForEmptyEventLoop = false 'bedeutet, dass die Funktion beim Aufruf des Callbacks angehalten (aber nicht' terminiert ') wird. Aber es kann für eine ziemlich lange Zeit in der Lambda-Welt herumhängen (mindestens 25 Minuten von meinen Tests). Wenn Sie die Funktion während dieser Zeit erneut aufrufen, wird sie effektiv wieder zum Leben erweckt, wobei alle Variablen ihre ursprünglichen Werte beibehalten. Dies ist der Fall, wenn 'firebase.apps.length == 1' ist, sodass keine erneute Initialisierung erforderlich ist. Bin ich in der Nähe? – dsl101

+0

Entschuldigung für die Flut. Ein letzter Gedanke. Ist es einfacher, den Aufruf von 'firebase.initializeApp()' außerhalb der Handler-Funktion zu verschieben (wie in der Antwort von @ paul-richter)? "Firebase.apps.length" muss nicht getestet werden, und meine Tests zeigen an, dass es immer noch die 'eingefrorene' Version verwendet - der erste Aufruf benötigt ~ 2300ms, um ein Ergebnis von Firebase zu erhalten, aber nachfolgende Aufrufe dauern etwa 100ms, was darauf hindeutet bereits authentifiziert – dsl101

2

Eine weitere Alternative, wenn Sie einen Knoten-basierte Entwicklungs-Setup verwenden ist das node-lambda Paket von here zu verwenden. Im Wesentlichen bietet es Wrapper zum Einrichten, Testen und Bereitstellen für Lambda. node-lambda deploy wird alle installierten Module (z. B. mit npm i --save firebase) zusammenpacken und sicherstellen, dass sie auf Lambda selbst verfügbar sind. Ich habe es sehr hilfreich für die Verwaltung externer Module gefunden.

2

2017-03-22 edit: google gerade angekündigt firebase cloud functions, die eine viel bessere Möglichkeit ist, dies zu tun. Cloud-Funktionen funktionieren genauso wie Lambda und können von Firebase-Ereignissen ausgelöst werden.


Hier ist meine Lösung the REST api mit (so brauchen Sie nicht zu require alles):

var https = require('https'); 
var firebaseHost = "yourapp.firebaseio.com"; 
function fbGet(key){ 
    return new Promise((resolve, reject) => { 
    var options = { 
     hostname: firebaseHost, 
     port: 443, 
     path: key + ".json", 
     method: 'GET' 
    }; 
    var req = https.request(options, function (res) { 
     res.setEncoding('utf8'); 
     var body = ''; 
     res.on('data', function(chunk) { 
     body += chunk; 
     }); 
     res.on('end', function() { 
     resolve(JSON.parse(body)) 
     }); 
    }); 
    req.end(); 
    req.on('error', reject); 
    }); 
} 

function fbPut(key, value){ 
    return new Promise((resolve, reject) => { 
    var options = { 
     hostname: firebaseHost, 
     port: 443, 
     path: key + ".json", 
     method: 'PUT' 
    }; 

    var req = https.request(options, function (res) { 
     console.log("request made") 
     res.setEncoding('utf8'); 
     var body = ''; 
     res.on('data', function(chunk) { 
     body += chunk; 
     }); 
     res.on('end', function() { 
     resolve(body) 
     }); 
    }); 
    req.end(JSON.stringify(value)); 
    req.on('error', reject); 
    }); 
} 

Sie es wie folgt verwenden können:

fbPut("/foo/bar", "lol").then(res => { 
    console.log("wrote data") 
}) 

Und dann:

fbGet("/foo/bar").then(data => { 
    console.log(data); // prints "lol" 
}).catch(e => { 
    console.log("error saving to firebase: "); 
    console.log(e); 
}) 
+1

Ich möchte die REST API verwenden, es ist die beste Lösung, aber ich habe Probleme mit der Authentifizierung. Ich brauche ein Zugriffs-Token und ich finde es sehr schwierig, eine gute Dokumentation dazu zu finden. Ich habe viele eigene Dokumente verfolgt und konnte bis jetzt noch nichts arbeiten – Francisc0

1

Für mich sollte Firebase-Admin den Trick machen. https://firebase.google.com/docs/admin/setup

Vielen Dank für Josiah Choi für Context.callbackWaitsForEmptyEventLoop vorschlagen. Daher muss Lambda nicht jedes Mal Firebase initialisieren. Mein erster Lauf war sehr langsam.

var firebase = require('firebase-admin'); 
    module.exports.Test = (event, context, callback) => { 

    context.callbackWaitsForEmptyEventLoop = false; //<---Important 

    if(firebase.apps.length == 0) { // <---Important!!! In lambda, it will cause double initialization. 
    firebase.initializeApp({ 
     credential: firebase.credential.cert("serviceAccount.json"), 
     databaseURL: <YOUR FIREBASE URL> 
    }); 

    } 


firebase.database().ref('conversation').once('value').then(function(snapshot) { 
    console.log (snapshot.val()) ; 
    var bodyReturn = { 
    input: snapshot.val() 
    } ; 

    callback(null,bodyReturn); 
    context.succeed() ; 
}); 

}; 
0

Nach ein paar Dinge zu versuchen, dies scheint für mich zu arbeiten (v 3.10.8):

for(var i=0;i<5;i++) 
{ 

    var firebase = require('firebase'); 
    var config = { 
     apiKey: "", 
     authDomain: "", 
     databaseURL: "", 
     storageBucket: "", 
     messagingSenderId: "" 
     }; 
     if(firebase.apps) 
     if(firebase.apps.length==0) 
     firebase.initializeApp(config) 

     firebase.database().ref().child("test").once('value'). 
      then(function(snapshot) { 
      console.log(snapshot.val()); 

           }); 

    }