Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transaction stuck after first step execution #39

Open
timemanx opened this issue Dec 15, 2024 · 3 comments
Open

Transaction stuck after first step execution #39

timemanx opened this issue Dec 15, 2024 · 3 comments

Comments

@timemanx
Copy link

Hi,

I'm using the transaction API but it seems the transaction always gets stuck after executing the first step.
I'm using EdgeDB 5.6 on EdgeDB Cloud and Java client library version 0.3.0.

Here is a simple example using Kotlin.

package com.test.edgedbclient

import com.edgedb.driver.EdgeDBClient
import com.edgedb.driver.EdgeDBConnection
import kotlinx.coroutines.future.await

suspend fun main() {
    val client = EdgeDBClient(EdgeDBConnection.parse(null, null, true))
    val output = client.transaction { tx ->
        tx.query(String::class.java, "SELECT 'Hello, World 1!'")
            .thenCompose {
                println("Output0: $it")
                tx.query(String::class.java, "SELECT 'Hello, World 2!'")
            }
            .thenCompose {
                println("Output1: $it")
                tx.query(String::class.java, "SELECT 'Hello, World 3!'")
            }
    }.await()

    println("--- Completed ---")
    println("Final output: $output")
    client.close()
}

The output is Output0: [Hello, World 1!] from the first step and then it's stuck.

I believe this is happening due to the semaphore in TransactionImpl being acquired

private <T, U> CompletionStage<U> executeTransaction(
Class<T> cls,
String query,
@Nullable Map<String, Object> args,
EnumSet<Capabilities> capabilities,
@NotNull QueryDelegate<T, U> delegate
) {
final AtomicInteger attempts = new AtomicInteger();
return CompletableFuture.runAsync(() -> {
try {
semaphore.acquire();
} catch (InterruptedException e) {
throw new CompletionException(e);
}
}).thenCompose((v) -> executeTransactionStep(cls, query, args, capabilities, attempts, delegate));
}

but never being released in the executeTransactionStep method after completion of the step.
private <T, U> CompletionStage<U> executeTransactionStep(
Class<T> cls,
String query,
@Nullable Map<String, Object> args,
EnumSet<Capabilities> capabilities,
@NotNull AtomicInteger attempts,
@NotNull QueryDelegate<T, U> delegate
) {
return CompletableFuture.completedFuture(null)
.thenCompose((v) ->
delegate.run(cls, query, args, capabilities)
.thenApply(t -> (CompletionStage<U>)CompletableFuture.completedFuture(t))
.exceptionally(e -> {
if(e instanceof EdgeDBException) {
if(((EdgeDBException) e).shouldRetry) {
if(attempts.getAndIncrement() <= settings.getRetryAttempts()) {
return executeTransactionStep(cls, query, args, capabilities, attempts, delegate);
}
}
}
return CompletableFuture.failedFuture(new TransactionException("Transaction failed after" + settings.getRetryAttempts() + "attempt(s)", e));
})
).thenCompose(v -> v);
}

This issue could be the same as #21.

Please let me know if any other details are required.

Thanks

@timemanx
Copy link
Author

I can get it to work by calling semaphore.release() in whenComplete().

-).thenCompose(v -> v);
+)
+.thenCompose(v -> v)
+.whenComplete((result, error) -> {
+    semaphore.release();  // Release in both success and failure cases
+});

on this line

Not sure whether it can cause any side-effects though.

@timemanx
Copy link
Author

timemanx commented Dec 18, 2024

@quinchs Any possibility of a fix soon?

@KageRiyuu
Copy link

Facing same issue, by when it can be fixed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants