firebase / firebase/firebase-cpp-sdk

[Bug] Nested `Future::OnCompletion` appears to deadlock

Đang mở
#1,621 1 bình luận 0 reaction 0 người được giao Xem trên GitHub
new type: question
Ngôn ngữ chính
C++
Star
326
Fork
137
Merge trung bình
3 ngày 9 giờ
Pull request đã merge (30 ngày)
5

Mô tả

### [REQUIRED] Please fill in the following fields:

* Pre-built Firebase C++ SDK version: 12.1.0
* Problematic Firebase Component: Future/Functions
* Platform you are using the C++ SDK on: Mac
* Platform you are targeting: Desktop

### [REQUIRED] Please describe the issue here:

As the title says, nested `Future::OnCompletion` appears to deadlock.

I have created a sample project reproducing this problem at:
https://github.com/DistroAV/firebase-functions-future-async-nested

I have a very simple firebase function running in an emulator (the same problem happens when published to project too):
```JavaScript
exports.foo = onCall((data, context) => {
return 200;
});
```

I then have C++ code to call this:
```C++
firebase::Future CallAsync(const char *name, const firebase::Variant &data,
std::function
completion_callback)
{
cout << "tid=" << pthread_self() << " +Cloud::Call(`" << name << "`, ...)" << endl;
firebase::Future future;
if (functions_) {
auto httpcallref = functions_->GetHttpsCallable(name);
cout << "tid=" << pthread_self() << " Call: `" << name << "` +Call(...)" << endl;
future = httpcallref.Call(data);
cout << "tid=" << pthread_self() << " Call: `" << name << "` -Call(...)" << endl;
future.OnCompletion(
[completion_callback](
const firebase::Future<
firebase::functions::
HttpsCallableResult>
&future) {
OnCallCompleted(future,
completion_callback);
});
}
cout << "tid=" << pthread_self() << " -Cloud::Call(`" << name << "`, ...)" << endl;
return future;
}

firebase::Variant OnCallCompleted(
const firebase::Future &future,
std::function
completion_callback)
{
cout << "tid=" << pthread_self() << " +OnCallCompleted(...)" << endl;
firebase::Variant data;
auto status = future.status();
cout << "tid=" << pthread_self() << " OnCallCompleted: status=" << status << endl;
if (status == firebase::kFutureStatusComplete) {
auto httpcallresult = future.result();
auto error = future.error();
auto error_message = future.error_message();
if (error == 0) {
data = httpcallresult->data();
}
if (completion_callback) {
completion_callback(data, error, error_message);
}
}
cout << "tid=" << pthread_self() << " -OnCallCompleted(...)" << endl;
return data;
}

firebase::Future FooAsync(std::function completion_callback)
{
cout << "tid=" << pthread_self() << " +FooAsync(...)" << endl;
auto future = CallAsync("foo", firebase::Variant(),
[completion_callback](const firebase::Variant &data,
int error, const std::string &) {
int value = (error == 0) ? data.int64_value() : -1;
if (completion_callback) {
completion_callback(value);
}
});
cout << "tid=" << pthread_self() << " -FooAsync(...)" << endl;
return future;
}

int main() {
...
future = FooAsync([](int value) {
cout << "tid=" << pthread_self() << " FooAsync #3: value=" << value << endl;
FooAsync([](int value) {
cout << "tid=" << pthread_self() << " FooAsync #4: value=" << value << endl;
});
});
WaitForCompletion(future);
return 0;
}
```

When I run the code I get the following:
```bash
% ./FirebaseExample
WARNING: Database URL not set in the Firebase config.
DEBUG: Creating Firebase App __FIRAPP_DEFAULT for Firebase C++ 12.1.0
DEBUG: Validating semaphore creation.
DEBUG: Added app name=__FIRAPP_DEFAULT: options, api_key=..., app_id=..., database_url=, messaging_sender_id=..., storage_bucket=..., project_id=... (0x...)
Using Functions Emulator at 127.0.0.1:5001
...
tid=0x1fefccc00 +FooAsync(...)
tid=0x1fefccc00 +Cloud::Call(`foo`, ...)
tid=0x1fefccc00 Call: `foo` +Call(...)
DEBUG: Calling Cloud Function with url: 127.0.0.1:5001/functions-futures-async-nested/us-central1/foo
data: {"data":null}
tid=0x1fefccc00 Call: `foo` -Call(...)
DEBUG: Cloud Function response body = {"result":200}
tid=0x16b7fb000 +OnCallCompleted(...)
tid=0x16b7fb000 FooAsync #3: value=200
tid=0x16b7fb000 +FooAsync(...)
tid=0x16b7fb000 +Cloud::Call(`foo`, ...)
^C
```
The app appears to deadlock and never complete the future and print the expected `FooAsync #4: value=200`.
I have to Ctrl-C to end the app.

The above is simplified code for this Issue.
In my actual code I also show initializing the project app and successful multiple non-async and non-nested async calls.

#### Steps to reproduce:

100% repro with the code/steps listed above

#### Relevant Code:

https://github.com/DistroAV/firebase-functions-future-async-nested

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

Bắt đầu với dự án tái hiện được liên kết và lần theo các entry point CallAsync, OnCallCompleted, FooAsync và WaitForCompletion. Tái hiện trường hợp Future::OnCompletion lồng nhau trên Mac với Firebase C++ SDK 12.1.0, sau đó so sánh với các lệnh gọi không lồng nhau thực hiện thành công. Được xem là hoàn tất khi callback FooAsync lồng nhau hoàn thành và in ra giá trị mong đợi thay vì bị treo.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
cpp, firebase
Lĩnh vực
api, backend
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
35/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.