2016-05-19 20 views
11

ottengo 'Impossibile trovare il modulo 'Firebase' quando provo a fare funzionare questo Lambda (Node.js 4,3)Amazon Lambda a Firebase

var Firebase = require('firebase'); 

Stessa cosa succede quando si tenta di caricare un pacchetto zippato che include node_modules/firebase

Qualcuno ha un'implementazione di "scrittura da lambda a firebase"?

risposta

9

ho risolto il mio problema utilizzando Firebase 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

Questo è in ritardo, ma nel caso in cui qualcun altro è alla ricerca:

Zippare cartella del progetto al posto dei contenuti della cartella di progetto può causare questo. La cartella zippata, una volta estratta, non dovrebbe contenere una cartella con i file lambda al suo interno, ma dovrebbe avere il file index.js e la cartella node_modules a livello di root.

un esempio di lavoro di una funzione lambda è (che utilizza l'ultimo materiale lucido Firebase * sigh *):

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); 
    }); 
}; 

Ora per l'avvertimento. Ho sperimentato questo causando il timeout della funzione lambda anche dopo che è avvenuta la richiamata firebase, ad es. la funzione set sembra creare un listener che mantiene aperta la funzione lambda nonostante il ritorno dei dati corretti.

Aggiornamento: chiamata a firebase.database(). GoOffline() risolve il problema di timeout della funzione Lambda che si verificava.

Le normali precauzioni relative alla sicurezza non vengono verificate o appropriate e si applicano le possibilità di arrestare lo spazio e il tempo utilizzando questo.

+0

sto lavorando sulla mia macchina locale al momento (in java script), ma anche la mia funzione si è bloccata alla fine. goOffline() non funziona nel mio caso. Come l'hai risolto? –

+0

sto lavorando al mio computer locale al momento (nello script java), ma alla fine la mia funzione si è bloccata. goOffline() non funziona nel mio caso. Come l'hai risolto? –

+1

@ risposta di josiah-choi sotto risolto il problema per me - vedi 'context.callbackWaitsForEmptyEventLoop = false' – dsl101

16

Per utilizzare in modo sicuro pacchetto Firebase NPM (versione 3.3.0) di AWS Lambda (Nodejs 4.3), eseguire le seguenti operazioni:

'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

Questo ha risolto un problema con cui stavo lottando. Come mai hai trovato queste 2 gemme per far funzionare Firebase? E ancora non capisco il secondo ('fireabase.apps.length == 0') - secondo i miei registri, è sempre e solo 0, ma se non lo faccio, va a finire. Quindi so che ho bisogno di farlo, ma voglio davvero sapere _why_. – dsl101

+0

OK - alcune speculazioni (sono nuovo in Lambda): 'context.callbackWaitsForEmptyEventLoop = false' indica che la funzione verrà sospesa (ma non 'termindated') quando viene richiamato il callback. Ma potrebbe rimanere in giro per Lambda-world per un periodo piuttosto lungo (almeno 25 minuti dai miei test). Se si richiama di nuovo la funzione durante questo periodo, viene effettivamente riportata in vita con tutte le variabili che mantengono i loro valori originali, e questo è quando 'firebase.apps.length == 1', quindi non è necessario inizializzarlo di nuovo. Sono vicino? – dsl101

+0

Ci scusiamo per l'alluvione. Un ultimo pensiero Spostare la chiamata a 'firebase.initializeApp()' al di fuori della funzione di gestione (come per la risposta di @ paul-richter) rende questo più semplice? Non è necessario testare 'firebase.apps.length', e il mio test indica che sta ancora usando la versione 'congelata' - la prima chiamata richiede ~ 2300ms per ottenere un risultato da Firebase, ma le chiamate successive richiedono circa 100ms, suggerendo che sono già autenticato – dsl101

2

Un'altra alternativa se si sta utilizzando una configurazione di sviluppo basato sui nodi è utilizzare il pacchetto node-lambda da here. In sostanza fornisce wrapper per impostare, testare e distribuire su lambda. node-lambda deploy impacchetterà tutti i moduli che hai installato (ad es. Con npm i --save firebase) e assicurati che siano disponibili su Lambda stessa. L'ho trovato davvero utile per la gestione dei moduli esterni.

2

2017-03-22 modifica: google ha appena annunciato firebase cloud functions, che è un modo molto migliore per farlo. Le funzioni cloud funzionano come lambda e possono essere attivate dagli eventi Firebase.


Ecco la mia soluzione con the REST api (quindi non c'è bisogno di require nulla):

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); 
    }); 
} 

è possibile utilizzarlo in questo modo:

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

E poi:

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

Voglio utilizzare l'API REST, è la soluzione migliore ma ho problemi con l'autenticazione. Ho bisogno di ottenere un token di accesso e trovo molto difficile trovare una buona documentazione su questo. Ho seguito molti dei loro documenti e non sono ancora riuscito a far funzionare nulla – Francisc0

1

Per me firebase-admin dovrebbe fare il trucco. https://firebase.google.com/docs/admin/setup

Grazie per Josiah Choi per aver suggerito context.callbackWaitsForEmptyEventLoop. Quindi lambda non ha bisogno di inizializzare Firebase ogni volta. La mia prima esecuzione è stata molto lenta.

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

Dopo aver provato un paio di cose, questo sembra funzionare per me (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()); 

           }); 

    }