I have the same problem, but I’m using the Java client (2.2.3) and testing on CB4.0.
Writing a single document and retrieving it by submitting a n1ql query does not work in a predictable way.
Same result using STATEMENT_PLUS consistency.
If many documents are persisted, the server hangs for a while and just returns an empty array.
My feeling is that the query times up while waiting for the index to be up to date with the latest writes.
However, the response doesn’t indicate any time out info, which makes it impossible to attempt a retry approach (because it is not possible to distinguish between a query that has returned 0 elements because there are no and one that has timed out while wait for the index to update).
@moon0326 we have some integration test using REQUEST_PLUS in the java client suite and they pass, do you think its possible to create a reproducible code/test case that I can run and see whats going on there?
Thank you for the follow up. I will try to come up with a code sample soon.
My tests are passing now after I started using n1ql for everything (including flushing documents). I will dig into the code sample I was using.
I realized that this might not be an issue with scan_consistency at all and it is such an edge case. It only happens when I flush, drop the primary index, and re-create the primary index. I really don’t expect to do that on production. Even in test environment, deleting documents with n1ql works just fine.
@moon0326 hm, this smells a lot like Loading... or a variation of this. I’ll try to reproduce your code locally and if I can open a new issue if there is not a duplicate yet.
Request plus scan consistency is not working as expected
Steps (multiple threads are performing the following steps at the same time):
Query by n1ql with “request plus” scan consistency a document A
If it does not exist then create the document A
Expected behaviour:
The document A is created once and not several times
Current result:
Several A documents are created despite the request plus setting.
If it has the same key just one is created and the rest get the “document already exist exception” but this is not our case.
Considerations:
The key of the document is different in each iteration.
We tried to simulate that failing scenario and realized that the request plus works perfect with a delay of more than 40ms between the first request and the second one.
Workaround:
At the beginning of the process we check if a custom document exists getting by key. If not, create a document with an expiration time of 2 seconds and a unique key that identifies the user performing the action so that further requests get ignored if that doc exists. That way we keep consistent data in our database.
Questions:
Any solution for the request plus?
Is it ok our workaround?
Thanks in advance!
Java code snippet to test the problem:
public static void main(String... args) throws Exception {
Cluster cluster = CouchbaseCluster.create(DefaultCouchbaseEnvironment.create(), "localhost");
Bucket bucket = cluster.openBucket("requestplus");
bucket.bucketManager().createN1qlPrimaryIndex(true, false);
new Thread(() -> queryAndCreate(bucket, 1)).start();
//Thread.sleep(40);
new Thread(() -> queryAndCreate(bucket, 2)).start();
new Thread(() -> queryAndCreate(bucket, 3)).start();
new Thread(() -> queryAndCreate(bucket, 4)).start();
}
private static void queryAndCreate(Bucket bucket, int i) {
try {
int docId = 1;
JsonObject placeholderValues = JsonObject.create().put("id", docId);
N1qlParams n1qlParams = N1qlParams.build().consistency(ScanConsistency.REQUEST_PLUS);
N1qlQueryResult result = bucket.query(N1qlQuery.parameterized("SELECT name FROM requestplus WHERE id = $id", placeholderValues, n1qlParams));
List<String> lista = result.allRows().stream().map(row -> row.value().getString("name")).collect(Collectors.toList());
final String data = lista.isEmpty() ? null : lista.get(0);
System.out.println("query " + i + " " + data);
if (data == null) {
JsonObject user = JsonObject.create().put("id", i).put("name", "carlos " + i);
bucket.insert(JsonDocument.create("u:" + i, user));
System.out.println("query " + i + " created the user");
}
} catch(DocumentAlreadyExistsException ex) {
System.out.println("document exist exception: error query: " + i);
}
}
thanks for the quick response. It seems to be ok what we are doing right now because it is similar to the cisco’s lock as explained in the video right?