场景:并发更新

Karbor原生代码更新Plan的Resource是先把Plan的所有Resource置为deleted,然后再创建新的创建接口。当并发在Plan在添加同一个资源时,由于没有锁机制,可能导致该资源被添加两次。具体代码如下:

def _plan_resources_update(context, plan_id, resources, session=None):
    session = session or get_session()
    now = timeutils.utcnow()
    with session.begin():
        model_query(
            context,
            models.Resource,
            session=session
        ).filter_by(
            plan_id=plan_id
        ).update({
            'deleted': True,
            'deleted_at': now,
            'updated_at': literal_column('updated_at')
        })
    resources_list = []
    for resource in resources:
        resource['plan_id'] = plan_id
        resource['resource_id'] = resource.pop('id')
        resource['resource_type'] = resource.pop('type')
        resource['resource_name'] = resource.pop('name')
        resource['resource_extra_info'] = resource.pop(
            'extra_info', None)
        resource_ref = _resource_create(context, resource)
        resources_list.append(resource_ref)

    return resources_list

解决该问题可以用行锁机制,限制对同一个Plan进行并发更新,具体讲就是Plan更新接口会起一个事务(Python里面是session),这个session会使用with_for_update接口查询该Plan,这样在事务结束前,无法并发对该Plan进行查询或修改。具体修改如下:

def plan_update(context, plan_id, values):
    session = get_session()
    with session.begin():
        session.query(models.Plan).filter_by(id=plan_id). \
            with_for_update().first()
        resources = values.get('resources')
        if resources is not None:
            _plan_resources_update(context,
                                   plan_id,
                                   values.pop('resources'),
                                   session=session)

        plan_ref = _plan_get(context, plan_id, session=session)
        plan_ref.update(values)

        return plan_ref

results matching ""

    No results matching ""