首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在TTL删除项后,COSMOS DB唯一的索引约束违反

在TTL删除项后,COSMOS DB唯一的索引约束违反
EN

Stack Overflow用户
提问于 2022-04-04 13:40:38
回答 1查看 204关注 0票数 0

我正在创建一个分布式锁库,使用蔚蓝-弹簧-启动-启动-宇宙。

我的库有两个方法: public void lockResource(String resourceUniqueIdentifier)和

公共空unlockResource(String resourceUniqueIdentifier)

lockResource()方法将接收我希望锁定的资源的resourceUniqueIdentifier,创建Lock()实例并将其保存在db中。

如果锁已经存在(通过在azure门户中将/appName设置为分区键,将/lockedResourceId设置为唯一键),则lockRepository.save()方法将抛出一个带有409状态代码的异常(因为已经存在一个具有相同分区键和唯一键的实体)。

因此,为了获得锁,先前获得锁的人需要调用unlockResource(String resourceUniqueIdentifier)或资源上的ttl需要过期(我还在lock dto上设置了一个ttl字段,并在蔚蓝门户中启用了它)

我的逻辑将尝试使用while(!isNewLock(锁) && isNotMaximumRetries(retries,resourceUniqueIdentifier))获取锁。下面是完整代码

Cosmos Config:具有“会话”一致性级别的直接模式

问题:即使某个资源的锁由于TTL过期而从数据库中删除(假设前面有其他服务/线程获得了锁),当再次尝试获取锁时,它仍然会抛出一个带有409状态代码的CosmosAccessException。(“唯一索引约束违反”)。对我来说,虽然锁已经从db中删除(因为我检查过了),但它仍然有一些关于该锁的其他信息。

锁DTO (我没有添加getter和setter):

代码语言:javascript
复制
@Container(containerName = "distributed-lock", timeToLive = -1, autoCreateContainer = false)

公共类锁{

代码语言:javascript
复制
@Id
@GeneratedValue
private String id;

private  String lockedResourceId;

@PartitionKey
private  String appName;

private  Integer ttl;

private long time;

public Lock(String id, String lockedResourceId, String appName, Integer ttl, long time) {
    this.id = id;
    this.lockedResourceId = lockedResourceId;
    this.appName = appName;
    this.ttl = ttl;
    this.time = time; //todo remove
}

}

LockService:

代码语言:javascript
复制
 public void lockResource(String resourceUniqueIdentifier) {
    var retries = 0;
    var lock = new Lock(UUID.randomUUID().toString(), resourceUniqueIdentifier, appName, lockProperties.getTtl(), Instant.now().toEpochMilli());

    while(!isNewLock(lock) && isNotMaximumRetries(retries, resourceUniqueIdentifier)) {
        logger.info(I9001.getMessage(), lock.getLockedResourceId(), retries);
        waitToUnlock();
        retries++;
    }
}




private void waitToUnlock() {
    try {
        Thread.sleep(lockProperties.getRetryInterval());
    } catch (InterruptedException e) {
        throw new RuntimeException("Interrupted exception while waiting to retry lock", e);
    }
}



private boolean isNewLock(Lock lockResource) {
    try {
        lockResource.setId(UUID.randomUUID().toString());
        var lock = lockRepository.save(lockResource);
        logger.info(LoggingUtil.X900.getMessage(), lock.getId());
        logger.info("SAVED LOCK WITH ID: {}", lock.getId());
        var sameLock = lockRepository.getByLockedResourceIdAndAppName(lockResource.getLockedResourceId(), lockResource.getAppName());
        logger.info("TESTED SAVED LOCK WITH ID: {}, UniqueId: {}", sameLock.getId(), sameLock.getLockedResourceId());

        return true;
    } catch (CosmosAccessException cosmosAccessException) {
        if (cosmosAccessException.getCosmosException().getStatusCode() == CONFLICT_STATUS_CODE) {
            lockResource.setTime(Instant.now().toEpochMilli());
            logger.info(LoggingUtil.X900.getMessage(), lockResource.getLockedResourceId(), lockResource.getId());
            var alreadyExisting = lockRepository.getByLockedResourceIdAndAppName(lockResource.getLockedResourceId(), lockResource.getAppName());
            logger.info("Retrieved duplicate with resId {} and id {}", alreadyExisting, alreadyExisting);

            return false;
        }
       else throw cosmosAccessException;
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-04-05 10:46:29

问题是,当资源离开的时间到期时,cosmos只执行部分删除。如果有人调用该资源,那么它将不会被返回,因为ttl过期了。但是,如果您想在经过少量的(在容器上设置了一些约束,如uniqueKey和partitionKey)之后保存相同的资源,您可能会收到409状态代码,因为当有足够的资源单元可用时,数据将被完全删除。

https://learn.microsoft.com/bs-latn-ba/azure/cosmos-db/sql/time-to-live?view=sql-server-ver15

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71738272

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档