2016-05-19 2 views
11

я получаю «Не удается найти модуль„firebase“, когда я пытаюсь запустить это в лямбда (Node.js 4.3)Amazon Lambda к Firebase

var Firebase = require('firebase'); 

То же самое происходит, когда я пытаюсь загрузить заархивированный пакет, который включает в себя node_modules/firebase

Есть ли у кого-нибудь работающая реализация от лямбды до firebase?

ответ

9

Я решил свою проблему с помощью 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

Это поздно, но в случае, если кто-то ищет:

Архивирование папку проекта вместо содержание в папке проекта может вызвать это. Зашифрованная папка при извлечении не должна содержать папку с файлами лямбда в ней, но должна иметь файл index.js и папку node_modules на корневом уровне.

Рабочий пример функции лямбда (используя последние блестящие firebase материал * Вздох *):

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

Теперь предостережением. Я испытал это, заставив лямбда-функцию на время ожидания даже после того, как произошел обратный вызов firebase, т.е. функция набора, похоже, создает слушатель, который удерживает лямбда-функцию открытой, несмотря на возвращение правильных данных.

Обновление: вызов firebase.database(). GoOffline() исправляет ошибку тайм-аута функции лямбда, которую я испытывал.

Обычные предостережения о безопасности, которые не проверяются или не подходят, а также возможности остановки пространства и времени с помощью этого применения.

+0

Я работаю на моей локальной машине в данный момент (в Java Script), но моя функция также застряла в конце. goOffline() не работает в моем случае. Как вы это исправили? –

+0

Я работаю на своей локальной машине в данный момент (в скрипте java), но моя функция также застряла в конце. goOffline() не работает в моем случае. Как вы это исправили? –

+1

@ Ответ josiah-choi ниже решил проблему для меня - см. 'Context.callbackWaitsForEmptyEventLoop = false' – dsl101

16

Чтобы безопасно использовать firebase НПМ пакет (версия 3.3.0) в AWS Lambda (Nodejs 4.3), пожалуйста, сделайте следующее:

'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

Это решило проблему, с которой я боролся. Как, на самом деле, вы нашли эти 2 камня для того, чтобы заставить рабочую станцию ​​работать? И я до сих пор не понимаю второй ('fireabase.apps.length == 0') - согласно моим журналам, это только 0, но если я не делаю этого теста, время истекает. Поэтому я знаю, что я сделал это, но хочу знать _why_. – dsl101

+0

ОК - некоторые предположения (я новичок в лямбда): 'context.callbackWaitsForEmptyEventLoop = false' означает, что функция будет приостановлена ​​(но не« завершена ») при вызове обратного вызова. Но это может повесить в Лямбда-мире довольно долго (по крайней мере, 25 минут после моего тестирования). Если вы вызовете функцию снова в течение этого времени, она будет эффективно возвращена к жизни со всеми переменными, содержащими их исходные значения, и это когда 'firebase.apps.length == 1', поэтому нет необходимости снова инициализировать. Я близко? – dsl101

+0

Извините за потоп. Последняя мысль. Перемещает ли вызов 'firebase.initializeApp()' вне функции обработчика (согласно ответу @ paul-richter) сделать это проще? Нет необходимости тестировать 'firebase.apps.length', и мое тестирование указывает, что оно все еще использует« замороженную »версию - первый вызов занимает ~ 2300 мс, чтобы получить результат от firebase, но последующие вызовы занимают около 100 мс, предполагая, что они уже аутентифицирован. – dsl101

2

Другой альтернативой, если вы используете настройки развития узла на основе является для использования пакета node-lambda от here. По сути, он предоставляет обертки для настройки, тестирования и развертывания в лямбда. node-lambda deploy упакует все модули, которые вы установили (например, с npm i --save firebase) и убедитесь, что они доступны на самой Лямбде. Я нашел, что это действительно полезно для управления внешними модулями.

2

2017-03-22 изменить: google только что объявлено firebase cloud functions, что намного лучший способ сделать это. Облачные функции работают так же, как лямбда, и могут запускаться из событий firebase.


Вот мое решение, используя the REST api (так что вам не нужно require ничего):

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

Вы можете использовать его как это:

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

А потом:

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

Я хочу использовать REST API, это лучшее решение, но у меня проблемы с аутентификацией. Мне нужно получить токен доступа, и мне очень сложно найти хорошую документацию по этому вопросу. Я следил за многими своими документами и еще ничего не смог получить – Francisc0

1

Для меня firebase-admin должен сделать трюк. https://firebase.google.com/docs/admin/setup

Спасибо за Josiah Choi за предложение context.callbackWaitsForEmptyEventLoop. Поэтому lambda не нужно инициализировать Firebase каждый раз. Мой первый запуск был очень медленным.

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

Перепробовав несколько вещей, это, кажется, работает для меня (об 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()); 

           }); 

    }