Skip to content

Commit a32ca6a

Browse files
committed
feat(jni): handle async operation failure
Add nativeAsyncOperationFailed JNI callback to each interface client. When Java reports a failed async operation, log a warning with error details and fulfill the pending promise with a default value. Add FullfillPromiseWithDefaultValue to MethodHelper. Look up the promise by GUID, remove it from the map, and call FulfillWithDefaultValue on the IPromiseHolder base. Without this, a failed Java async operation leaves its TPromise unfulfilled, deadlocking any game-thread code that calls TFuture::Get().
1 parent 5971082 commit a32ca6a

File tree

39 files changed

+951
-0
lines changed

39 files changed

+951
-0
lines changed

goldenmaster/Plugins/Counter/Source/CounterJni/Private/Generated/Detail/CounterMethodHelper.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,41 @@ class FCounterMethodHelper
4848
}
4949
}
5050

51+
bool FulfillPromiseWithDefaultValue(const FGuid& InId)
52+
{
53+
UE_LOG(
54+
LogCounterMethodHelper_JNI,
55+
Verbose,
56+
TEXT("Resolving promise %s with default value for %s"),
57+
*(InId.ToString(EGuidFormats::Digits)),
58+
*OwnerName);
59+
60+
TUniquePtr<ICounterPromiseHolder> PromiseHolderPtr;
61+
{
62+
FScopeLock Lock(&ReplyPromisesMapCS);
63+
if (auto* Found = ReplyPromisesMap.Find(InId))
64+
{
65+
PromiseHolderPtr = MoveTemp(*Found);
66+
ReplyPromisesMap.Remove(InId);
67+
}
68+
}
69+
70+
if (PromiseHolderPtr)
71+
{
72+
PromiseHolderPtr->FulfillWithDefaultValue();
73+
return true;
74+
}
75+
76+
UE_LOG(
77+
LogCounterMethodHelper_JNI,
78+
Verbose,
79+
TEXT("No promise found for id %s in %s"),
80+
*(InId.ToString(EGuidFormats::Digits)),
81+
*OwnerName);
82+
83+
return false;
84+
}
85+
5186
template <typename ResultType>
5287
FGuid StorePromise(TPromise<ResultType>&& InPromise);
5388

goldenmaster/Plugins/Counter/Source/CounterJni/Private/Generated/Jni/CounterCounterJniClient.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,4 +1347,23 @@ JNI_METHOD void Java_counter_counterjniclient_CounterJniClient_nativeIsReady(JNI
13471347
}
13481348
localJniAccessor->notifyIsReady(value);
13491349
}
1350+
1351+
JNI_METHOD void Java_counter_counterjniclient_CounterJniClient_nativeAsyncOperationFailed(JNIEnv* Env, jclass Clazz, jstring callId, jstring errorMessage, jint errorCode)
1352+
{
1353+
FString callIdString = FJavaHelper::FStringFromParam(Env, callId);
1354+
static const TCHAR* errorMsgId = TEXT("failed to convert call id string in nativeAsyncOperationFailed for counter/counterjniclient/CounterJniClient");
1355+
if (CounterDataJavaConverter::CheckJniErrorOccurred(errorMsgId))
1356+
{
1357+
return;
1358+
}
1359+
FString errorMsgString = FJavaHelper::FStringFromParam(Env, errorMessage);
1360+
1361+
UE_LOG(LogCounterCounterClient_JNI, Warning,
1362+
TEXT("Async operation failed for id %s: %s (code: %d)"),
1363+
*callIdString, *errorMsgString, static_cast<int32>(errorCode));
1364+
1365+
FGuid guid;
1366+
FGuid::Parse(callIdString, guid);
1367+
gUCounterCounterJniClientmethodHelper.FulfillPromiseWithDefaultValue(guid);
1368+
}
13501369
#endif

goldenmaster/Plugins/CustomTypes/Source/CustomTypesJni/Private/Generated/Detail/CustomTypesMethodHelper.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,41 @@ class FCustomTypesMethodHelper
4848
}
4949
}
5050

51+
bool FulfillPromiseWithDefaultValue(const FGuid& InId)
52+
{
53+
UE_LOG(
54+
LogCustomTypesMethodHelper_JNI,
55+
Verbose,
56+
TEXT("Resolving promise %s with default value for %s"),
57+
*(InId.ToString(EGuidFormats::Digits)),
58+
*OwnerName);
59+
60+
TUniquePtr<ICustomTypesPromiseHolder> PromiseHolderPtr;
61+
{
62+
FScopeLock Lock(&ReplyPromisesMapCS);
63+
if (auto* Found = ReplyPromisesMap.Find(InId))
64+
{
65+
PromiseHolderPtr = MoveTemp(*Found);
66+
ReplyPromisesMap.Remove(InId);
67+
}
68+
}
69+
70+
if (PromiseHolderPtr)
71+
{
72+
PromiseHolderPtr->FulfillWithDefaultValue();
73+
return true;
74+
}
75+
76+
UE_LOG(
77+
LogCustomTypesMethodHelper_JNI,
78+
Verbose,
79+
TEXT("No promise found for id %s in %s"),
80+
*(InId.ToString(EGuidFormats::Digits)),
81+
*OwnerName);
82+
83+
return false;
84+
}
85+
5186
template <typename ResultType>
5287
FGuid StorePromise(TPromise<ResultType>&& InPromise);
5388

goldenmaster/Plugins/ExternTypes/Source/ExternTypesJni/Private/Generated/Detail/ExternTypesMethodHelper.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,41 @@ class FExternTypesMethodHelper
4848
}
4949
}
5050

51+
bool FulfillPromiseWithDefaultValue(const FGuid& InId)
52+
{
53+
UE_LOG(
54+
LogExternTypesMethodHelper_JNI,
55+
Verbose,
56+
TEXT("Resolving promise %s with default value for %s"),
57+
*(InId.ToString(EGuidFormats::Digits)),
58+
*OwnerName);
59+
60+
TUniquePtr<IExternTypesPromiseHolder> PromiseHolderPtr;
61+
{
62+
FScopeLock Lock(&ReplyPromisesMapCS);
63+
if (auto* Found = ReplyPromisesMap.Find(InId))
64+
{
65+
PromiseHolderPtr = MoveTemp(*Found);
66+
ReplyPromisesMap.Remove(InId);
67+
}
68+
}
69+
70+
if (PromiseHolderPtr)
71+
{
72+
PromiseHolderPtr->FulfillWithDefaultValue();
73+
return true;
74+
}
75+
76+
UE_LOG(
77+
LogExternTypesMethodHelper_JNI,
78+
Verbose,
79+
TEXT("No promise found for id %s in %s"),
80+
*(InId.ToString(EGuidFormats::Digits)),
81+
*OwnerName);
82+
83+
return false;
84+
}
85+
5186
template <typename ResultType>
5287
FGuid StorePromise(TPromise<ResultType>&& InPromise);
5388

goldenmaster/Plugins/TbEnum/Source/TbEnumJni/Private/Generated/Detail/TbEnumMethodHelper.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,41 @@ class FTbEnumMethodHelper
4848
}
4949
}
5050

51+
bool FulfillPromiseWithDefaultValue(const FGuid& InId)
52+
{
53+
UE_LOG(
54+
LogTbEnumMethodHelper_JNI,
55+
Verbose,
56+
TEXT("Resolving promise %s with default value for %s"),
57+
*(InId.ToString(EGuidFormats::Digits)),
58+
*OwnerName);
59+
60+
TUniquePtr<ITbEnumPromiseHolder> PromiseHolderPtr;
61+
{
62+
FScopeLock Lock(&ReplyPromisesMapCS);
63+
if (auto* Found = ReplyPromisesMap.Find(InId))
64+
{
65+
PromiseHolderPtr = MoveTemp(*Found);
66+
ReplyPromisesMap.Remove(InId);
67+
}
68+
}
69+
70+
if (PromiseHolderPtr)
71+
{
72+
PromiseHolderPtr->FulfillWithDefaultValue();
73+
return true;
74+
}
75+
76+
UE_LOG(
77+
LogTbEnumMethodHelper_JNI,
78+
Verbose,
79+
TEXT("No promise found for id %s in %s"),
80+
*(InId.ToString(EGuidFormats::Digits)),
81+
*OwnerName);
82+
83+
return false;
84+
}
85+
5186
template <typename ResultType>
5287
FGuid StorePromise(TPromise<ResultType>&& InPromise);
5388

goldenmaster/Plugins/TbEnum/Source/TbEnumJni/Private/Generated/Jni/TbEnumEnumInterfaceJniClient.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1456,4 +1456,23 @@ JNI_METHOD void Java_tbEnum_tbEnumjniclient_EnumInterfaceJniClient_nativeIsReady
14561456
}
14571457
localJniAccessor->notifyIsReady(value);
14581458
}
1459+
1460+
JNI_METHOD void Java_tbEnum_tbEnumjniclient_EnumInterfaceJniClient_nativeAsyncOperationFailed(JNIEnv* Env, jclass Clazz, jstring callId, jstring errorMessage, jint errorCode)
1461+
{
1462+
FString callIdString = FJavaHelper::FStringFromParam(Env, callId);
1463+
static const TCHAR* errorMsgId = TEXT("failed to convert call id string in nativeAsyncOperationFailed for tbEnum/tbEnumjniclient/EnumInterfaceJniClient");
1464+
if (TbEnumDataJavaConverter::CheckJniErrorOccurred(errorMsgId))
1465+
{
1466+
return;
1467+
}
1468+
FString errorMsgString = FJavaHelper::FStringFromParam(Env, errorMessage);
1469+
1470+
UE_LOG(LogTbEnumEnumInterfaceClient_JNI, Warning,
1471+
TEXT("Async operation failed for id %s: %s (code: %d)"),
1472+
*callIdString, *errorMsgString, static_cast<int32>(errorCode));
1473+
1474+
FGuid guid;
1475+
FGuid::Parse(callIdString, guid);
1476+
gUTbEnumEnumInterfaceJniClientmethodHelper.FulfillPromiseWithDefaultValue(guid);
1477+
}
14591478
#endif

goldenmaster/Plugins/TbIfaceimport/Source/TbIfaceimportJni/Private/Generated/Detail/TbIfaceimportMethodHelper.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,41 @@ class FTbIfaceimportMethodHelper
4848
}
4949
}
5050

51+
bool FulfillPromiseWithDefaultValue(const FGuid& InId)
52+
{
53+
UE_LOG(
54+
LogTbIfaceimportMethodHelper_JNI,
55+
Verbose,
56+
TEXT("Resolving promise %s with default value for %s"),
57+
*(InId.ToString(EGuidFormats::Digits)),
58+
*OwnerName);
59+
60+
TUniquePtr<ITbIfaceimportPromiseHolder> PromiseHolderPtr;
61+
{
62+
FScopeLock Lock(&ReplyPromisesMapCS);
63+
if (auto* Found = ReplyPromisesMap.Find(InId))
64+
{
65+
PromiseHolderPtr = MoveTemp(*Found);
66+
ReplyPromisesMap.Remove(InId);
67+
}
68+
}
69+
70+
if (PromiseHolderPtr)
71+
{
72+
PromiseHolderPtr->FulfillWithDefaultValue();
73+
return true;
74+
}
75+
76+
UE_LOG(
77+
LogTbIfaceimportMethodHelper_JNI,
78+
Verbose,
79+
TEXT("No promise found for id %s in %s"),
80+
*(InId.ToString(EGuidFormats::Digits)),
81+
*OwnerName);
82+
83+
return false;
84+
}
85+
5186
template <typename ResultType>
5287
FGuid StorePromise(TPromise<ResultType>&& InPromise);
5388

goldenmaster/Plugins/TbNames/Source/TbNamesJni/Private/Generated/Detail/TbNamesMethodHelper.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,41 @@ class FTbNamesMethodHelper
4848
}
4949
}
5050

51+
bool FulfillPromiseWithDefaultValue(const FGuid& InId)
52+
{
53+
UE_LOG(
54+
LogTbNamesMethodHelper_JNI,
55+
Verbose,
56+
TEXT("Resolving promise %s with default value for %s"),
57+
*(InId.ToString(EGuidFormats::Digits)),
58+
*OwnerName);
59+
60+
TUniquePtr<ITbNamesPromiseHolder> PromiseHolderPtr;
61+
{
62+
FScopeLock Lock(&ReplyPromisesMapCS);
63+
if (auto* Found = ReplyPromisesMap.Find(InId))
64+
{
65+
PromiseHolderPtr = MoveTemp(*Found);
66+
ReplyPromisesMap.Remove(InId);
67+
}
68+
}
69+
70+
if (PromiseHolderPtr)
71+
{
72+
PromiseHolderPtr->FulfillWithDefaultValue();
73+
return true;
74+
}
75+
76+
UE_LOG(
77+
LogTbNamesMethodHelper_JNI,
78+
Verbose,
79+
TEXT("No promise found for id %s in %s"),
80+
*(InId.ToString(EGuidFormats::Digits)),
81+
*OwnerName);
82+
83+
return false;
84+
}
85+
5186
template <typename ResultType>
5287
FGuid StorePromise(TPromise<ResultType>&& InPromise);
5388

goldenmaster/Plugins/TbNames/Source/TbNamesJni/Private/Generated/Jni/TbNamesNamEsJniClient.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -960,4 +960,23 @@ JNI_METHOD void Java_tbNames_tbNamesjniclient_NamEsJniClient_nativeIsReady(JNIEn
960960
}
961961
localJniAccessor->notifyIsReady(value);
962962
}
963+
964+
JNI_METHOD void Java_tbNames_tbNamesjniclient_NamEsJniClient_nativeAsyncOperationFailed(JNIEnv* Env, jclass Clazz, jstring callId, jstring errorMessage, jint errorCode)
965+
{
966+
FString callIdString = FJavaHelper::FStringFromParam(Env, callId);
967+
static const TCHAR* errorMsgId = TEXT("failed to convert call id string in nativeAsyncOperationFailed for tbNames/tbNamesjniclient/NamEsJniClient");
968+
if (TbNamesDataJavaConverter::CheckJniErrorOccurred(errorMsgId))
969+
{
970+
return;
971+
}
972+
FString errorMsgString = FJavaHelper::FStringFromParam(Env, errorMessage);
973+
974+
UE_LOG(LogTbNamesNamEsClient_JNI, Warning,
975+
TEXT("Async operation failed for id %s: %s (code: %d)"),
976+
*callIdString, *errorMsgString, static_cast<int32>(errorCode));
977+
978+
FGuid guid;
979+
FGuid::Parse(callIdString, guid);
980+
gUTbNamesNamEsJniClientmethodHelper.FulfillPromiseWithDefaultValue(guid);
981+
}
963982
#endif

goldenmaster/Plugins/TbRefIfaces/Source/TbRefIfacesJni/Private/Generated/Detail/TbRefIfacesMethodHelper.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,41 @@ class FTbRefIfacesMethodHelper
4848
}
4949
}
5050

51+
bool FulfillPromiseWithDefaultValue(const FGuid& InId)
52+
{
53+
UE_LOG(
54+
LogTbRefIfacesMethodHelper_JNI,
55+
Verbose,
56+
TEXT("Resolving promise %s with default value for %s"),
57+
*(InId.ToString(EGuidFormats::Digits)),
58+
*OwnerName);
59+
60+
TUniquePtr<ITbRefIfacesPromiseHolder> PromiseHolderPtr;
61+
{
62+
FScopeLock Lock(&ReplyPromisesMapCS);
63+
if (auto* Found = ReplyPromisesMap.Find(InId))
64+
{
65+
PromiseHolderPtr = MoveTemp(*Found);
66+
ReplyPromisesMap.Remove(InId);
67+
}
68+
}
69+
70+
if (PromiseHolderPtr)
71+
{
72+
PromiseHolderPtr->FulfillWithDefaultValue();
73+
return true;
74+
}
75+
76+
UE_LOG(
77+
LogTbRefIfacesMethodHelper_JNI,
78+
Verbose,
79+
TEXT("No promise found for id %s in %s"),
80+
*(InId.ToString(EGuidFormats::Digits)),
81+
*OwnerName);
82+
83+
return false;
84+
}
85+
5186
template <typename ResultType>
5287
FGuid StorePromise(TPromise<ResultType>&& InPromise);
5388

0 commit comments

Comments
 (0)