0

Use Case :-

We are using Spring-data-aerospike to get and set the aerospike record. At the same time we have multiple Kafka consumers who are trying to update the different fields of a single record.

Problem :- We are facing the challenge of Dirt-read problem. The records are getting overwritten.

At t-0, Consumer-1 reads the Record-1, with intent to update the Field-name(mobileNumber). 
Record-1 looks like something :(custId:1, mobileNumber:1234567890, custType:PERMANENT)

At t-1, Consumer-2 reads the Record-1, with intent to update the Field-2(custType). 

At t-3, Consumer-2 commits the Record-1, with updated value for custType. 
Record-1 looks like something :(custId:1, mobileNumber:1234567890, custType:PERM_CHANGED_2)

At t-4, Consumer-1 commits the Record-1, with updated value for mobileNumber. 
Record-1 looks like something :(custId:1, mobileNumber:9988776655, custType:PERMANENNT)

The problem here is : The updated value of 'custType' by Consumer-2 got lost at t=4.

Here is code-snippet looks like :-


@Document(collection = "cust", expiration = 90, expirationUnit = TimeUnit.DAYS)
public class Customer {

   @Id
   @Field(value = "PK")
   private String custId;

   @Field(value = "mobileNumber")
   private String mobileNumber;

   @Field(value = "custType")
   private String custType;
 
}




@Repository
public interface CustomerRepository extends AerospikeRepository<Customer, String> {

  // Working.
  List<Customer> findById(String primaryKeyId);

}



@Autowired
AerospikeTemplate aerospikeTemplate;


@Transactional(isolation = Isloation.SERIALIZABLE, rollbackFor=Exception.class)
public ResponseDTO<String> updateCustomer(CustomerUpdateRequest custUpdateReqDTO) {
   Optional<Customer> cust = customerRepository.findById(custUpdateReqDTO.getCustId());
   // Update Business logic by consumers.
   aerospikeTemplate.update(cust);
}

Here is dependencies looks like :-

<dependency>
            <groupId>com.aerospike</groupId>
            <artifactId>aerospike-client</artifactId>
            <version>4.1.3</version>
        </dependency>

        <dependency>
            <groupId>com.aerospike</groupId>
            <artifactId>spring-data-aerospike</artifactId>
            <version>${aerospike.data.version}</version>
            <scope>system</scope>
            <systemPath>${basedir}/lib/spring-data-aerospike-2.0.0.RELEASE.jar</systemPath>
        </dependency>

        <dependency>
            <groupId>com.aerospike</groupId>
            <artifactId>aerospike-client</artifactId>
        </dependency>
        <dependency>
            <groupId>com.aerospike</groupId>
            <artifactId>aerospike-helper-java</artifactId>
            <version>1.2.2</version>
        </dependency>

Questions :-

We are aware that spring transactional works with RDBMS !! Whats the way to get the transactional property working here in this scenario ??

Any help or suggestions shall be highly appreciated !

Aditya Goel
  • 201
  • 1
  • 15
  • 1
    you need to use optimistic locking for that, please read about `spring data/jpa optimistic locking`. for that you should add to your document class `@Version private long version;`. it will prevent concurrent update, and if it happened, you will catch `OptimisticLockingFailureException` and retry read-update again – Vasyl Sarzhynskyi Jul 04 '20 at 10:48
  • Thanks for response. Does the usage of @Version also works with NoSql databases like aerospike as well ?? – Aditya Goel Jul 04 '20 at 16:27
  • 1
    yes, `@Version` works fine for `spring-data-aerospike` as well – Vasyl Sarzhynskyi Jul 04 '20 at 17:49
  • * I am nowhere using the EntityManager to manage my entities. So, how would the optimistic locking is managed ? * Is my understanding correct : Whenever an entity has a @Version annotated field, optimistic locking should be enabled automatically on the entity ?? But, I don't have even Entity annotation for my aerospike set ! Would this still work ? – Aditya Goel Jul 05 '20 at 08:16
  • 1
    in case with `spring-data-aerospike`, you use `@Document` instead of `@Entity`. `@Version private long version;` will work out of the box. – Vasyl Sarzhynskyi Jul 05 '20 at 08:53
  • Thank you very much. Appreciate your response. Alright. let me put it into action & will post the workable code. – Aditya Goel Jul 06 '20 at 05:10
  • @VasylSarzhynskyi : Its not throwing the "OptimisticLockingFailureException". We need to get the record again from aerospike just before going to update it. With that extra call of GET (Just before UPDATE), we are getting the updated version-Number (in case another consumer updated the same record). Would that be the perfect way to proceed with this ? But we still can get the error in some specific scenario ! – Aditya Goel Jul 08 '20 at 07:16
  • 1
    still, without optimistic locking you will have race conditions, bad approach. strange that in your case exception not throwing, I used it earlier and it worked fine. please do the following experiment: save document in DB with manually set version = 5. and after that try to update the same record in DB with version = 4. isn't it throw exception? – Vasyl Sarzhynskyi Jul 08 '20 at 07:20
  • @VasylSarzhynskyi We solved it using the aerospikeRepository.save method. In this case, its throwing us the OptimisticLockingFailureException. While we use the aerospikeTemplate.save method, it doesn't throws the exception ! Thank you very much for your assistance. We are glad and highly appreciate your response ! Meanwhile, Can you help us addressing these concerns as well :- https://stackoverflow.com/questions/62727064/spring-data-aerospike-findbyattribute-operation-working-mysteriously How should I accept this answer here ? – Aditya Goel Jul 08 '20 at 08:09

1 Answers1

0

We solved it using the aerospikeRepository.save method. In this case, its throwing us the OptimisticLockingFailureException, if a particular record is being updated by more than 2 consumers parallelly !!

While we use the aerospikeTemplate.update method, it doesn't throws any exception !

Thank you very much for your assistance @VasylSarzhynskyi. We are glad and highly appreciate your response !

Aditya Goel
  • 201
  • 1
  • 15