5

Tôi đang xây dựng một kỹ năng Alexa, yêu cầu tôi phải nghe Cơ sở dữ liệu thời gian thực Firebase. Trong một phần cụ thể của kỹ năng, tôi cần phải viết một đối tượng JSON vào Firebase, bao gồm hai trường, "ý định", với một giá trị không đáng kể và "đã hoàn thành", với giá trị là false. Sau đó, tôi đợi một thiết bị khác nghe cơ sở dữ liệu này để đăng ký thay đổi này, tại thời điểm đó nó tạo ra một trường khác, có tên là "kết quả", với một số giá trị số và thay đổi giá trị "đã hoàn thành" thành true.Lắng nghe cơ sở dữ liệu Firebase trong AWS Lambda lần

Sau đó, chức năng gốc (test1) phải nhận ra khi giá trị "thực hiện" là đúng và sau đó truy xuất giá trị của "kết quả".

Điều tôi đang gặp phải là có chức năng thực hiện tất cả các thao tác đọc/ghi này trước khi chức năng chính (không đồng bộ) của tôi kết thúc. Như tiêu đề cho thấy, AWS Lambda lần vì lý do nào đó, và tôi không thể đọc giá trị của "kết quả".

Đây là chức năng Tôi đang sử dụng:

function test1(intentName, targetRef, context) { 
    console.log("writing"); 
    targetRef.set({ 
     intent: intentName, 
     done: false 
    }).then(function() { 
     return targetRef.orderByChild("done").equalTo(true).on("value"); 
    }).then(function(snapshot) { 
     var res = snapshot.val().result; 
     console.log("Res: " + res); 
     context.succeed(//context.succeed should be called after "result" has a value. 
      generateResponse(
       buildSpeechletReponse("The result is" + processNumbersForSpeech(res), true), 
       {} 
      ) 
     ); 
    }); 
} 

Đây là sản phẩm của giao diện điều khiển (trong AWS Lambda):

 
20:05:31 
START RequestId: a25d2354-d9cb-11e6-b80a-f35142a5f45f Version: $LATEST 
20:05:31 
2017-01-13T20:05:31.464Z a25d2354-d9cb-11e6-b80a-f35142a5f45f writing 
 
20:05:35 
END RequestId: a25d2354-d9cb-11e6-b80a-f35142a5f45f 
 
20:05:35 
REPORT RequestId: a25d2354-d9cb-11e6-b80a-f35142a5f45f Duration: 4001.15 ms Billed Duration: 4000 ms Memory Size: 128 MB Max Memory Used: 39 MB 
 
20:05:35 
2017-01-13T20:05:35.335Z a25d2354-d9cb-11e6-b80a-f35142a5f45f Task timed out after 4.00 seconds 

Sau đây là cấu trúc của dữ liệu căn cứ hỏa lực:

enter image description here

"thực hiện" ban đầu là sai. Khi thiết bị kia thêm "kết quả", nó cũng cập nhật giá trị "thực hiện" thành true. "148434459 ..." là targetRef.

Trợ giúp của bạn thực sự được đánh giá cao. Tôi sẽ cung cấp thêm thông tin nếu cần.

+0

Hy vọng câu trả lời của tôi ở đây sẽ giúp https://stackoverflow.com/a/45266181/2073325 – gchao

Trả lời

0

Hàm lambda của bạn có thể hết sau 4 giây vì bạn đặt giá trị này khi định cấu hình hàm Lambda. Để cho hàm của bạn chờ đợi điều bên ngoài xảy ra, bạn có thể lên lịch một hàm để truy vấn giá trị thường xuyên với setTimeout() cho đến khi giá trị ở đó. Nếu mất hơn 4 giây, bạn cũng cần phải tăng thời gian chờ của chức năng.

+0

Rất tiếc, tôi đã cố gắng đặt thời gian chờ tối đa 20 giây và không hiệu quả. Trong bảng điều khiển Firebase, tôi thấy rằng "kết quả" xuất hiện trong chưa đầy một giây. –

1

Vấn đề là on không trả lại lời hứa. Thay vào đó, nó trả về hàm gọi lại đã được chuyển thành tham số. on sẽ gọi lại cuộc gọi lại cho dữ liệu ban đầu và sau đó lại cho bất kỳ thay đổi nào được thực hiện cho dữ liệu.

Bạn rất có thể muốn sử dụng once, mà trả về một lời hứa:

... 
}).then(function() { 
    return targetRef.orderByChild("done").equalTo(true).once("value"); 
}).then(function (snapshot) { 
    snapshot.forEach(function (childSnapshot) { 
     console.log(childSnapshot.val()); 
    }); 
}) 
... 

Lưu ý rằng ảnh chụp giải quyết của lời hứa sẽ chứa số không hay nhiều trẻ em phù hợp với truy vấn. Để liệt kê các trẻ em, bạn có thể sử dụng phương thức forEach của ảnh chụp nhanh.

+0

Khi tôi làm điều này, giao diện điều khiển in: "Chưa đọc: null", và sau đó "FIREBASE CẢNH BÁO: Sử dụng chỉ mục không xác định. Hãy xem xét thêm" .indexOn ":" done "tại targetRef vào quy tắc bảo mật của bạn để có hiệu suất tốt hơn –

+2

Cập nhật câu trả lời Gọi 'val()' trên ảnh chụp sẽ trả về một đối tượng chứa các khóa và giá trị con - vì vậy không có khoá 'result' trong đó. Cảnh báo là vì bạn chưa lập chỉ mục thuộc tính con ('done') bạn đang sử dụng trong truy vấn. Để biết điều đó, hãy xem [docs] (https://firebase.google.com/docs/database/security/indexing-data) – cartant

+0

Tôi hơi bối rối .. Vì vậy, tôi sẽ có thể đọc giá trị của "kết quả" Và cũng có thể, khi tôi gọi console.log (childSnapshot.val()), không có đầu ra –

0

Từ các tài liệu AWS Lambda:

Q: bao lâu có thể một chức năng AWS Lambda thực hiện?

Tất cả các cuộc gọi đến AWS Lambda phải hoàn tất việc thực hiện trong vòng 300 giây.Thời gian chờ mặc định là 3 giây, nhưng bạn có thể đặt thời gian chờ thành bất kỳ giá trị nào trong khoảng từ 1 đến 300 giây.

Tôi khuyên bạn nên gặp sự cố khi cố đợi sự kiện Firebase từ bên trong hàm Lambda. Lambda được thiết kế để được gọi với dữ liệu và xử lý dữ liệu và thoát ra, không phải chờ đợi cho các sự kiện khác xảy ra. Bạn nên sử dụng một số loại VPS và chạy một quy trình Node chung để thực hiện công việc cơ sở dữ liệu. Lambda đẩy dữ liệu vào Firebase là tốt, nhưng những gì bạn đang cố gắng đạt được với Firebase có thể là phương pháp sai.

+0

Ok. Tôi chỉ cố gắng đặt một thời gian chờ là 2 giây, và Firebase đã được cập nhật với "kết quả" trước đó. Điều đó vẫn còn có vấn đề? –

-1

Bạn đang gọi hàm trước khi chức năng khác được gọi. Hãy thử npm sleep() hoặc setTimeout() để tạm dừng chức năng của bạn.

1

Tôi phát hiện ra cách khởi tạo Firebase trong hàm lambda (ví dụ: thông qua firebase-admin) sẽ ngăn chức năng chấm dứt (cho đến thời gian chờ 6 giây mặc định) trừ khi bạn gọi app.delete() trên phiên bản ứng dụng firebase. Ngoài ra, bạn nên đảm bảo rằng mỗi lần chạy hàm lambda của bạn, bạn đang sử dụng một cá thể ứng dụng firebase mới nếu không bạn sẽ gặp phải sự cố.

const app = admin.initializeApp({}); 
app.database().ref('child').set('hello').then(() => { 
    return app.delete(); 
}).then(() => { 
    let response = {}; // whatever 
    callback(null, response); 
}); 
+0

Tôi hiểu ... Điều đó rất thú vị. Điều này có áp dụng ngay cả khi tôi không sử dụng firebase-admin không? –

+0

Ngoài ra, bạn làm gì bằng cách "sử dụng instace ứng dụng firebase mới?" Tôi có nên gọi 'firebase.initializeApp (config)' mỗi lần trước khi tôi chạy hàm lambda? Hiện tại, tôi không làm điều này. –

+0

@MikiP Tôi tin rằng mấu chốt của vấn đề là 'initializeApp' (cho dù sử dụng firebase-admin hay không) tạo ra một kết nối liên tục với firebase ngăn cản quá trình lambda thoát khỏi trừ khi kết nối được kết thúc thông qua' app.delete() ' . Vì vậy, bạn cần phải dọn dẹp kết nối firebase của bạn. Và có bạn nên gọi 'initializeApp' mỗi lần trong hàm lamba của bạn nếu không bạn có thể gặp lỗi" ứng dụng này đã bị xóa "nếu bạn đang khởi chạy firebase bên ngoài ngữ cảnh chức năng. – mattwindwer

Các vấn đề liên quan