diff --git a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc index db48bbdd8..497f94c08 100644 --- a/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc +++ b/modules/ROOT/pages/deprecations-additions-removals-compatibility.adoc @@ -296,6 +296,34 @@ RETURN cosh(0.5), coth(0.5), sinh(0.5), tanh(0.5) For more information, see xref:functions/mathematical-trigonometric.adoc[Mathematical functions - trigonometric]. |=== +[[cypher-deprecations-additions-removals-2025.03]] +== Neo4j 2025.03 + +=== New features + +[cols="2", options="header"] +|=== +| Feature +| Details + +a| +label:functionality[] +label:new[] +[source, cypher, role=noheader] +---- +UNWIND range(1, 100) AS i +CALL (i) { + MERGE (u:User {id: i}) + ON CREATE SET u.created = timestamp() +} IN TRANSACTIONS ON ERROR RETRY 1 SECOND THEN FAIL +---- + +| New error handling option for `CALL { ... } IN TRANSACTIONS`: `ON ERROR RETRY`. +This option applies an exponential delay between retries for transaction batches failing due to transient errors, with an optional maximum retry duration, and handles failure based on a specified fallback error mode if the transaction does not succeed within the given time. +For more information, see xref:subqueries/subqueries-in-transactions#on-error-retry[`CALL` subqueries in transactions -> `ON ERROR RETRY`]. + +|=== + [[cypher-deprecations-additions-removals-2025.01]] == Neo4j 2025.01 diff --git a/modules/ROOT/pages/subqueries/subqueries-in-transactions.adoc b/modules/ROOT/pages/subqueries/subqueries-in-transactions.adoc index 453dfa232..9a965302f 100644 --- a/modules/ROOT/pages/subqueries/subqueries-in-transactions.adoc +++ b/modules/ROOT/pages/subqueries/subqueries-in-transactions.adoc @@ -27,7 +27,7 @@ CALL { } IN [[concurrency] CONCURRENT] TRANSACTIONS [OF batchSize ROW[S]] [REPORT STATUS AS statusVar] -[ON ERROR {CONTINUE | BREAK | FAIL}]; +[ON ERROR {CONTINUE | BREAK | FAIL | RETRY [FOR] [duration SEC[OND[S]]] [THEN {CONTINUE | BREAK | FAIL}]}] ---- == Loading CSV data @@ -309,34 +309,34 @@ CALL (g) { ---- ==== - [[error-behavior]] == Error behavior -Users can choose one of three different option flags to control the behavior -in case of an error occurring in any of the inner transactions of `CALL { ... } IN TRANSACTIONS`: +`CALL { ... } IN TRANSACTIONS` has four different behavioral options in case an error occurs in any of the inner transactions: xref:subqueries/subqueries-in-transactions.adoc#on-error-continue[`ON ERROR CONTINUE`], xref:subqueries/subqueries-in-transactions.adoc#on-error-break[`ON ERROR BREAK`], xref:subqueries/subqueries-in-transactions.adoc#on-error-fail[`ON ERROR FAIL`], and xref:subqueries/subqueries-in-transactions.adoc#on-error-retry[`ON ERROR RETRY`]. + +[IMPORTANT] +If an error occurs, any inner transactions that were successfully committed remain unchanged and are not rolled back. However, any inner transactions that failed are fully rolled back. This behavior applies regardless of which `ON ERROR` option is used. + + +[[on-error-continue]] +=== `ON ERROR CONTINUE` -* `ON ERROR CONTINUE` to ignore a recoverable error and continue the execution of subsequent inner transactions. +`ON ERROR CONTINUE` ignores recoverable errors and continues the execution of subsequent inner transactions. The outer transaction succeeds. -It will cause the expected variables from the failed inner query to be bound as null for that specific transaction. -* `ON ERROR BREAK` to ignore a recoverable error and stop the execution of subsequent inner transactions. The outer transaction succeeds. -It will cause expected variables from the failed inner query to be bound as null for all onward transactions (including the failed one). -* `ON ERROR FAIL` to acknowledge a recoverable error and stop the execution of subsequent inner transactions. The outer transaction fails. This is the default behavior if no flag is explicitly specified. +When an inner query fails, `ON ERROR CONTINUE` ensures the outer transaction continues, returning `null` for the failed inner query. -[IMPORTANT] -==== -On error, any previously committed inner transactions remain committed, and are not rolled back. Any failed inner transactions are rolled back. -==== +.`ON ERROR CONTINUE` +===== -In the following example, the last subquery execution in the second inner transaction fails -due to division by zero. +In the below query, the last subquery execution in the second inner transaction fails +due to division by zero: -.Query +.Subquery with failing transaction [source, cypher, role=test-fail] ---- UNWIND [4, 2, 1, 0] AS i CALL (i) { - CREATE (:Person {num: 100/i}) + CREATE (:Person {num: 100/i}) // Note, fails when i = 0 } IN TRANSACTIONS OF 2 ROWS RETURN i ---- @@ -347,9 +347,9 @@ RETURN i / by zero (Transactions committed: 1) ---- -When the failure occurred, the first transaction had already been committed, so the database contains two example nodes. +Since the failure occurred after the first transaction was committed, the database retains the successfully created nodes. -.Query +.Return nodes created prior to failed transaction [source, cypher] ---- MATCH (e:Person) @@ -360,14 +360,16 @@ RETURN e.num [role="queryresult",options="header,footer",cols="1* SEC[OND[S]]`, where is an `INTEGER` or `FLOAT` value representing seconds that is greater than or equal to `0`. +Decimal values are allowed, and the `` can be set with a parameter. +Note that this `` overrides the default value. + +The duration timer starts when the first retry is scheduled. +As a result, regardless of the specified duration, a minimum of one retry will be attempted. +If the transaction still fails with a transient error, a new attempt with made unless the duration has expired. +For example, a value of `0` (or close to `0`) will result in a retry, but guarantees that only a single retry will be attempted. + +.Set a maximum time limit for retries +===== + +In this example, the retry duration is explicitly set to `2.5` seconds. +This means that the transaction will be retried until it succeeds or until `2.5` seconds have elapsed. + +.`ON ERROR RETRY` with a set duration +[source, cypher] +---- +UNWIND range(1, 100) AS i +CALL (i) { + MERGE (u:User {id: i}) + ON CREATE SET u.created = timestamp() +} IN TRANSACTIONS ON ERROR RETRY FOR 2.5 SECONDS +---- + +.Parameter +[source, parameters] +---- +{ + "duration": 10 +} +---- + +.`ON ERROR RETRY` using a parameter for the duration +[source, cypher] +---- +UNWIND range(1, 100) AS i +CALL (i) { + MERGE (u:User {id: i}) + ON CREATE SET u.created = timestamp() +} IN TRANSACTIONS ON ERROR RETRY FOR $duration SECONDS +---- +===== + + +[[fallback-error-handling]] +==== Fallback error handling options + +`ON ERROR RETRY` can be combined with the other xref:subqueries/subqueries-in-transactions.adoc#error-behavior[`ON ERROR` options] via the `THEN` clause to specify a fallback behavior. +The fallback behavior specifies what will happen if a transaction has not succeeded within the time limit. +Specifically: + +* `ON ERROR RETRY ... THEN CONTINUE`: the query will ignore recoverable errors and continue with the execution of subsequent inner transactions. +The outer transaction succeeds, and `null` will be returned for any failed inner transactions. +See xref:subqueries/subqueries-in-transactions.adoc#on-error-continue[`ON ERROR CONTINUE`] for more information about this behavior. + +* `ON ERROR RETRY ... THEN BREAK`: the query will ignore recoverable errors and stop the execution of subsequent inner transactions. +The outer transaction succeeds, and `null` will be returned for the failed inner transaction and all subsequent ones. +See xref:subqueries/subqueries-in-transactions.adoc#on-error-break[`ON ERROR BREAK`] for more information about this behavior. + +* `ON ERROR RETRY ... THEN FAIL` (default): the query will acknowledge a recoverable error and stop the execution of subsequent inner transactions, causing the outer transaction to fail. +See xref:subqueries/subqueries-in-transactions.adoc#on-error-fail[`ON ERROR FAIL`] for more information about this behavior. + +[NOTE] +Because `THEN FAIL` is the default fallback option it does not have to be specified. + +// tag::tabs[] +[.tabs] + +.ON ERROR RETRY THEN CONTINUE +[source,cypher] +---- +UNWIND range(1, 100) AS i +CALL (i) { + MERGE (u:User {id: i}) + ON CREATE SET u.created = timestamp() +} IN TRANSACTIONS ON ERROR RETRY FOR 1 SECOND THEN CONTINUE +---- + +.ON ERROR RETRY THEN BREAK +[source,cypher] +---- +UNWIND range(1, 100) AS i +CALL (i) { + MERGE (u:User {id: i}) + ON CREATE SET u.created = timestamp() +} IN TRANSACTIONS ON ERROR RETRY FOR 1 SECOND THEN BREAK +---- + +.ON ERROR RETRY THEN FAIL +[source,cypher] +---- +UNWIND range(1, 100) AS i +CALL (i) { + MERGE (u:User {id: i}) + ON CREATE SET u.created = timestamp() +} IN TRANSACTIONS ON ERROR RETRY FOR 1 SECOND THEN FAIL +---- + +// end::tabs[] + [[status-report]] == Status report @@ -516,7 +696,7 @@ The status value is a map value with the following fields: Example of reporting status with `ON ERROR CONTINUE`: .Query -[source, cypher, indent=0, role=test-result-skip] +[source, cypher, role=test-result-skip] ---- UNWIND [1, 0, 2, 4] AS i CALL (i) { @@ -526,7 +706,7 @@ CALL (i) { OF 1 ROW ON ERROR CONTINUE REPORT STATUS AS s -RETURN n.num, s; +RETURN n.num, s ---- .Result @@ -543,7 +723,7 @@ RETURN n.num, s; Example of reporting status with `ON ERROR BREAK`: .Query -[source, cypher, indent=0] +[source, cypher] ---- UNWIND [1, 0, 2, 4] AS i CALL (i) { @@ -553,7 +733,7 @@ CALL (i) { OF 1 ROW ON ERROR BREAK REPORT STATUS AS s -RETURN n.num, s.started, s.committed, s.errorMessage; +RETURN n.num, s.started, s.committed, s.errorMessage ---- .Result @@ -580,7 +760,7 @@ CALL (i) { OF 1 ROW ON ERROR FAIL REPORT STATUS AS s -RETURN n.num, s.errorMessage; +RETURN n.num, s.errorMessage ---- .Error @@ -658,10 +838,21 @@ For example, when creating or deleting a relationship, a write lock is taken on A deadlock happens when two transactions are blocked by each other because they are attempting to concurrently modify a node or a relationship that is locked by the other transaction (for more information about locks and deadlocks in Neo4j, see link:{neo4j-docs-base-uri}/operations-manual/current/database-internals/concurrent-data-access/#_locks[Operations Manual -> Concurrent data access]. A deadlock may occur when using `CALL { ... } IN CONCURRENT TRANSACTIONS` if the transactions for two or more batches try to take the same locks in an order that results in a circular dependency between them. -If so, the impacted transactions are always rolled back, and an error is thrown unless the query is appended with `ON ERROR CONTINUE` or `ON ERROR BREAK`. +If so, the impacted transactions are always rolled back, and an error is thrown unless the query is appended with one of the following error options: + +* xref:subqueries/subqueries-in-transactions.adoc#on-error-continue[`ON ERROR CONTINUE`] +* xref:subqueries/subqueries-in-transactions.adoc#on-error-break[`ON ERROR BREAK`] +* xref:subqueries/subqueries-in-transactions.adoc#on-error-retry[`ON ERROR RETRY`] label:new[Introduced in Neo4j 2025.03] + +The latter is particularly suited for concurrent transactions, because it retries recoverable transient errors with exponential backoff between retries until the xref:subqueries/subqueries-in-transactions.adoc#specify-retry-duration[maximum retry duration] has been reached. + +[NOTE] +Deadlock detection and transaction retries can be time-consuming. +When importing data that includes a significant number of relationships to be merged between the same nodes but processed in different batches, increasing the concurrency may not enhance performance. +On the contrary, it could slow down the import process. .Dealing with deadlocks -==== +===== The following query tries to create `Movie` and `Year` nodes connected by a `RELEASED_IN` relationship. Note that there are only three different years in the CSV file, meaning that only three `Year` nodes should be created. @@ -687,9 +878,6 @@ ForsetiClient[transactionId=64, clientId=12] can't acquire ExclusiveLock{owner=F Client[63] waits for [ForsetiClient[transactionId=64, clientId=12]]] ---- -The following query uses `ON ERROR CONTINUE` to bypass any deadlocks and continue with the execution of subsequent inner transactions. -It returns the `transactionID`, `commitStatus` and `errorMessage` of the failed transactions. - .Query using `ON ERROR CONTINUE` to ignore deadlocks and complete outer transaction [source, cypher] ---- @@ -707,68 +895,164 @@ RETURN status.transactionId AS transaction, status.committed AS commitStatus, st .Result [source, "queryresult"] ---- -+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| transaction | commitStatus | errorMessage | -+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| "neo4j-transaction-169" | FALSE | "ForsetiClient[transactionId=169, clientId=11] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=168, clientId=9]} on NODE_RELATIONSHIP_GROUP_DELETE(46) because holders of that lock are waiting for ForsetiClient[transactionId=169, clientId=11]. | -| | \ Wait list:ExclusiveLock[ | -| | \ Client[168] waits for [ForsetiClient[transactionId=169, clientId=11]]]" | -| "neo4j-transaction-169" | FALSE | "ForsetiClient[transactionId=169, clientId=11] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=168, clientId=9]} on NODE_RELATIONSHIP_GROUP_DELETE(46) because holders of that lock are waiting for ForsetiClient[transactionId=169, clientId=11]. | -| | \ Wait list:ExclusiveLock[ | -| | \ Client[168] waits for [ForsetiClient[transactionId=169, clientId=11]]]" | -| "neo4j-transaction-169" | FALSE | "ForsetiClient[transactionId=169, clientId=11] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=168, clientId=9]} on NODE_RELATIONSHIP_GROUP_DELETE(46) because holders of that lock are waiting for ForsetiClient[transactionId=169, clientId=11]. | -| | \ Wait list:ExclusiveLock[ | -| | \ Client[168] waits for [ForsetiClient[transactionId=169, clientId=11]]]" | -| "neo4j-transaction-169" | FALSE | "ForsetiClient[transactionId=169, clientId=11] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=168, clientId=9]} on NODE_RELATIONSHIP_GROUP_DELETE(46) because holders of that lock are waiting for ForsetiClient[transactionId=169, clientId=11]. | -| | \ Wait list:ExclusiveLock[ | -| | \ Client[168] waits for [ForsetiClient[transactionId=169, clientId=11]]]" | -| "neo4j-transaction-169" | FALSE | "ForsetiClient[transactionId=169, clientId=11] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=168, clientId=9]} on NODE_RELATIONSHIP_GROUP_DELETE(46) because holders of that lock are waiting for ForsetiClient[transactionId=169, clientId=11]. | -| | \ Wait list:ExclusiveLock[ | -| | \ Client[168] waits for [ForsetiClient[transactionId=169, clientId=11]]]" | -| "neo4j-transaction-169" | FALSE | "ForsetiClient[transactionId=169, clientId=11] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=168, clientId=9]} on NODE_RELATIONSHIP_GROUP_DELETE(46) because holders of that lock are waiting for ForsetiClient[transactionId=169, clientId=11]. | -| | \ Wait list:ExclusiveLock[ | -| | \ Client[168] waits for [ForsetiClient[transactionId=169, clientId=11]]]" | -| "neo4j-transaction-169" | FALSE | "ForsetiClient[transactionId=169, clientId=11] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=168, clientId=9]} on NODE_RELATIONSHIP_GROUP_DELETE(46) because holders of that lock are waiting for ForsetiClient[transactionId=169, clientId=11]. | -| | \ Wait list:ExclusiveLock[ | -| | \ Client[168] waits for [ForsetiClient[transactionId=169, clientId=11]]]" | -| "neo4j-transaction-169" | FALSE | "ForsetiClient[transactionId=169, clientId=11] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=168, clientId=9]} on NODE_RELATIONSHIP_GROUP_DELETE(46) because holders of that lock are waiting for ForsetiClient[transactionId=169, clientId=11]. | -| | \ Wait list:ExclusiveLock[ | -| | \ Client[168] waits for [ForsetiClient[transactionId=169, clientId=11]]]" | -| "neo4j-transaction-169" | FALSE | "ForsetiClient[transactionId=169, clientId=11] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=168, clientId=9]} on NODE_RELATIONSHIP_GROUP_DELETE(46) because holders of that lock are waiting for ForsetiClient[transactionId=169, clientId=11]. | -| | \ Wait list:ExclusiveLock[ | -| | \ Client[168] waits for [ForsetiClient[transactionId=169, clientId=11]]]" | -| "neo4j-transaction-169" | FALSE | "ForsetiClient[transactionId=169, clientId=11] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=168, clientId=9]} on NODE_RELATIONSHIP_GROUP_DELETE(46) because holders of that lock are waiting for ForsetiClient[transactionId=169, clientId=11]. | -| | \ Wait list:ExclusiveLock[ | -| | \ Client[168] waits for [ForsetiClient[transactionId=169, clientId=11]]]" | -+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ ----- - -.Click to see an example of failed transactions being retried using Cypher -[%collapsible] -===== -While failed transactions may be more efficiently retried using a link:{neo4j-docs-base-uri}/create-applications[driver], below is an example how failed transactions can be retried within the same Cypher query: ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| transaction | commitStatus | errorMessage | ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| "neo4j-transaction-486" | FALSE | "ForsetiClient[transactionId=486, clientId=8] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=485, clientId=13]} on NODE_RELATIONSHIP_GROUP_DELETE(18) because holders of that lock are waiting for ForsetiClient[transactionId=486, clientId=8]. | +| | \ Wait list:ExclusiveLock[ | +| | \ Client[485] waits for [ForsetiClient[transactionId=486, clientId=8]]]" | +| "neo4j-transaction-486" | FALSE | "ForsetiClient[transactionId=486, clientId=8] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=485, clientId=13]} on NODE_RELATIONSHIP_GROUP_DELETE(18) because holders of that lock are waiting for ForsetiClient[transactionId=486, clientId=8]. | +| | \ Wait list:ExclusiveLock[ | +| | \ Client[485] waits for [ForsetiClient[transactionId=486, clientId=8]]]" | +| "neo4j-transaction-486" | FALSE | "ForsetiClient[transactionId=486, clientId=8] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=485, clientId=13]} on NODE_RELATIONSHIP_GROUP_DELETE(18) because holders of that lock are waiting for ForsetiClient[transactionId=486, clientId=8]. | +| | \ Wait list:ExclusiveLock[ | +| | \ Client[485] waits for [ForsetiClient[transactionId=486, clientId=8]]]" | +| "neo4j-transaction-486" | FALSE | "ForsetiClient[transactionId=486, clientId=8] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=485, clientId=13]} on NODE_RELATIONSHIP_GROUP_DELETE(18) because holders of that lock are waiting for ForsetiClient[transactionId=486, clientId=8]. | +| | \ Wait list:ExclusiveLock[ | +| | \ Client[485] waits for [ForsetiClient[transactionId=486, clientId=8]]]" | +| "neo4j-transaction-486" | FALSE | "ForsetiClient[transactionId=486, clientId=8] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=485, clientId=13]} on NODE_RELATIONSHIP_GROUP_DELETE(18) because holders of that lock are waiting for ForsetiClient[transactionId=486, clientId=8]. | +| | \ Wait list:ExclusiveLock[ | +| | \ Client[485] waits for [ForsetiClient[transactionId=486, clientId=8]]]" | +| "neo4j-transaction-486" | FALSE | "ForsetiClient[transactionId=486, clientId=8] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=485, clientId=13]} on NODE_RELATIONSHIP_GROUP_DELETE(18) because holders of that lock are waiting for ForsetiClient[transactionId=486, clientId=8]. | +| | \ Wait list:ExclusiveLock[ | +| | \ Client[485] waits for [ForsetiClient[transactionId=486, clientId=8]]]" | +| "neo4j-transaction-486" | FALSE | "ForsetiClient[transactionId=486, clientId=8] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=485, clientId=13]} on NODE_RELATIONSHIP_GROUP_DELETE(18) because holders of that lock are waiting for ForsetiClient[transactionId=486, clientId=8]. | +| | \ Wait list:ExclusiveLock[ | +| | \ Client[485] waits for [ForsetiClient[transactionId=486, clientId=8]]]" | +| "neo4j-transaction-486" | FALSE | "ForsetiClient[transactionId=486, clientId=8] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=485, clientId=13]} on NODE_RELATIONSHIP_GROUP_DELETE(18) because holders of that lock are waiting for ForsetiClient[transactionId=486, clientId=8]. | +| | \ Wait list:ExclusiveLock[ | +| | \ Client[485] waits for [ForsetiClient[transactionId=486, clientId=8]]]" | +| "neo4j-transaction-486" | FALSE | "ForsetiClient[transactionId=486, clientId=8] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=485, clientId=13]} on NODE_RELATIONSHIP_GROUP_DELETE(18) because holders of that lock are waiting for ForsetiClient[transactionId=486, clientId=8]. | +| | \ Wait list:ExclusiveLock[ | +| | \ Client[485] waits for [ForsetiClient[transactionId=486, clientId=8]]]" | +| "neo4j-transaction-486" | FALSE | "ForsetiClient[transactionId=486, clientId=8] can't acquire ExclusiveLock{owner=ForsetiClient[transactionId=485, clientId=13]} on NODE_RELATIONSHIP_GROUP_DELETE(18) because holders of that lock are waiting for ForsetiClient[transactionId=486, clientId=8]. | +| | \ Wait list:ExclusiveLock[ | +| | \ Client[485] waits for [ForsetiClient[transactionId=486, clientId=8]]]" | ++-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +---- -[NOTE] -The query below uses xref:clauses/filter.adoc#filter-with-where[`FILTER`] (introduced in Neo4j 2025.04) as a replacement for `WITH * WHERE `. +These are transient errors, meaning that re-running the transactions may be successful. +To retry the any failed inner transactions, use the error option `ON ERROR RETRY`, which retries any failing transactions until the maximum retry duration has been reached. -.Query retrying failed transactions +The following query uses `ON ERROR RETRY ... THEN CONTINUE` to retry the above query for a maximum of `3` seconds and then continue the execution of subsequent inner transactions by ignoring any recoverable errors. + +.Query using `ON ERROR RETRY ... THEN CONTINUE` to retry deadlocked inner transactions and complete outer transaction [source, cypher] ---- LOAD CSV WITH HEADERS FROM 'https://data.neo4j.com/importing-cypher/movies.csv' AS row CALL (row) { - MERGE (m:Movie {movieId: row.movieId}) - MERGE (y:Year {year: row.year}) - MERGE (m)-[r:RELEASED_IN]->(y) -} IN 2 CONCURRENT TRANSACTIONS OF 10 ROWS ON ERROR CONTINUE REPORT STATUS as status -FILTER status.committed = false -CALL (row) { - MERGE (m:Movie {movieId: row.movieId}) - MERGE (y:Year {year: row.year}) - MERGE (m)-[r:RELEASED_IN]->(y) -} IN 2 CONCURRENT TRANSACTIONS OF 10 ROWS ON ERROR FAIL + MERGE (m:Movie {movieId: row.movieId}) + MERGE (y:Year {year: row.year}) + MERGE (m)-[r:RELEASED_IN]->(y) +} IN 2 CONCURRENT TRANSACTIONS OF 10 ROWS ON ERROR RETRY THEN CONTINUE FOR 3 SECONDS REPORT STATUS AS status +RETURN status.transactionID as transaction, status.committed AS successfulTransaction ---- + +The result shows that all transactions are now successful: + +.Result +[source, "queryresult"] +---- ++-------------------------------------------------+ +| transaction | successfulTransaction | ++-------------------------------------------------+ +| "neo4j-transaction-500" | TRUE | +| "neo4j-transaction-500" | TRUE | +| "neo4j-transaction-500" | TRUE | +| "neo4j-transaction-500" | TRUE | +| "neo4j-transaction-500" | TRUE | +| "neo4j-transaction-500" | TRUE | +| "neo4j-transaction-500" | TRUE | +| "neo4j-transaction-500" | TRUE | +| "neo4j-transaction-500" | TRUE | +| "neo4j-transaction-500" | TRUE | +| "neo4j-transaction-501" | TRUE | +| "neo4j-transaction-501" | TRUE | +| "neo4j-transaction-501" | TRUE | +| "neo4j-transaction-501" | TRUE | +| "neo4j-transaction-501" | TRUE | +| "neo4j-transaction-501" | TRUE | +| "neo4j-transaction-501" | TRUE | +| "neo4j-transaction-501" | TRUE | +| "neo4j-transaction-501" | TRUE | +| "neo4j-transaction-501" | TRUE | +| "neo4j-transaction-502" | TRUE | +| "neo4j-transaction-502" | TRUE | +| "neo4j-transaction-502" | TRUE | +| "neo4j-transaction-502" | TRUE | +| "neo4j-transaction-502" | TRUE | +| "neo4j-transaction-502" | TRUE | +| "neo4j-transaction-502" | TRUE | +| "neo4j-transaction-502" | TRUE | +| "neo4j-transaction-502" | TRUE | +| "neo4j-transaction-502" | TRUE | +| "neo4j-transaction-504" | TRUE | +| "neo4j-transaction-504" | TRUE | +| "neo4j-transaction-504" | TRUE | +| "neo4j-transaction-504" | TRUE | +| "neo4j-transaction-504" | TRUE | +| "neo4j-transaction-504" | TRUE | +| "neo4j-transaction-504" | TRUE | +| "neo4j-transaction-504" | TRUE | +| "neo4j-transaction-504" | TRUE | +| "neo4j-transaction-504" | TRUE | +| "neo4j-transaction-503" | TRUE | +| "neo4j-transaction-503" | TRUE | +| "neo4j-transaction-503" | TRUE | +| "neo4j-transaction-503" | TRUE | +| "neo4j-transaction-503" | TRUE | +| "neo4j-transaction-503" | TRUE | +| "neo4j-transaction-503" | TRUE | +| "neo4j-transaction-503" | TRUE | +| "neo4j-transaction-503" | TRUE | +| "neo4j-transaction-503" | TRUE | +| "neo4j-transaction-505" | TRUE | +| "neo4j-transaction-505" | TRUE | +| "neo4j-transaction-505" | TRUE | +| "neo4j-transaction-505" | TRUE | +| "neo4j-transaction-505" | TRUE | +| "neo4j-transaction-505" | TRUE | +| "neo4j-transaction-505" | TRUE | +| "neo4j-transaction-505" | TRUE | +| "neo4j-transaction-505" | TRUE | +| "neo4j-transaction-505" | TRUE | +| "neo4j-transaction-506" | TRUE | +| "neo4j-transaction-506" | TRUE | +| "neo4j-transaction-506" | TRUE | +| "neo4j-transaction-506" | TRUE | +| "neo4j-transaction-506" | TRUE | +| "neo4j-transaction-506" | TRUE | +| "neo4j-transaction-506" | TRUE | +| "neo4j-transaction-506" | TRUE | +| "neo4j-transaction-506" | TRUE | +| "neo4j-transaction-506" | TRUE | +| "neo4j-transaction-507" | TRUE | +| "neo4j-transaction-507" | TRUE | +| "neo4j-transaction-507" | TRUE | +| "neo4j-transaction-507" | TRUE | +| "neo4j-transaction-507" | TRUE | +| "neo4j-transaction-507" | TRUE | +| "neo4j-transaction-507" | TRUE | +| "neo4j-transaction-507" | TRUE | +| "neo4j-transaction-507" | TRUE | +| "neo4j-transaction-507" | TRUE | +| "neo4j-transaction-508" | TRUE | +| "neo4j-transaction-508" | TRUE | +| "neo4j-transaction-508" | TRUE | +| "neo4j-transaction-508" | TRUE | +| "neo4j-transaction-508" | TRUE | +| "neo4j-transaction-508" | TRUE | +| "neo4j-transaction-508" | TRUE | +| "neo4j-transaction-508" | TRUE | +| "neo4j-transaction-508" | TRUE | +| "neo4j-transaction-508" | TRUE | +| "neo4j-transaction-509" | TRUE | +| "neo4j-transaction-509" | TRUE | +| "neo4j-transaction-509" | TRUE | ++-------------------------------------------------+ +---- + ===== -==== [[restrictions]] == Restrictions