2016-08-02 9 views
1

는 다음 사항을 고려 버그 :이이 같은 노드 JS 과정에서 호출중포 기지 거래

function useCredits(userId, amount){ 
    var userRef = firebase.database().ref().child('users').child(userId); 
    userRef.transaction(function(user) { 

     if (!user){ 
      return user; 
     } 
     user.credits -= amount; 
     return user; 


    }, NOOP, false); 
} 

function notifyUser(userId, message){ 

    var notificationId = Math.random(); 
    var userNotificationRef = firebase.database().ref().child('users').child(userId).child('notifications').child(notificationId); 
    userNotificationRef.transaction(function(notification) { 

     return message; 

    }, NOOP, false); 
} 

.

는 사용자는 다음과 같습니다

{ 
    "name": 'Alex', 
    "age": 22, 
    "credits": 100, 
    "notifications": { 
    "1": "notification 1", 
    "2": "notification 2" 
    } 
} 

내 스트레스 테스트를 실행하면 내가 가끔 userRef 트랜잭션 업데이트 함수에 전달 된 사용자 개체는 단지 다음 인 전체 사용자가 아닌 것을 알 수 :

{ 

    "notifications": { 
    "1": "notification 1", 
    "2": "notification 2" 
    } 
} 

이것은 분명히 user.credits가 없기 때문에 오류가 발생합니다.

userRef 트랜잭션의 업데이트 기능에 전달 된 사용자 객체가 userNotificationRef 트랜잭션의 업데이트 기능에 의해 반환 된 데이터와 동일하다는 것은 의심스러운 사실입니다.

왜 이런 경우입니까? 이 문제는 사용자 상위 위치에서 두 트랜잭션을 모두 실행하면 사라지지만이 방법은 전체 사용자 개체를 효과적으로 잠그고 읽는 것과 같이 덜 최적의 솔루션입니다.이 개체는 한 번만 쓰는 알림을 추가 할 때 중복됩니다.

답변

3

제 경험상, 트랜잭션 업데이트 함수에 전달 된 초기 값에 의존 할 수는 없습니다. 데이터가 데이터 저장소에 채워지더라도 함수는 null, 부분 값 또는 이전의 오래된 값 (로컬 업데이트의 경우)으로 호출 될 수 있습니다. 가짜 업데이트가 거절되고 트랜잭션이 재 시도되기 때문에 함수를 작성할 때 방어적인 접근 방식을 취하는 한 일반적으로 문제가되지 않습니다.

하지만 조심 : 당신은 데이터가 이해가되지 않기 때문에 (undefined 반환하여) 거래를 중단하는 경우는, 다음은 서버에 대해 확인 하지 그리고 시도되지 않습니다. 이런 이유로 트랜잭션을 중단하지 않는 것이 좋습니다. 나는이 픽스 (및 다른 것들)를 투명하게 적용하기 위해 monkey patch을 만들었다; 브라우저 전용이지만 노드에 쉽게 적용 할 수 있습니다.

조금 더 돕기 위해 할 수있는 또 다른 일은 on('value') 호출을 트랜잭션 바로 전에 동일한 참조 번호에 삽입하고 트랜잭션이 완료 될 때까지 활성 상태로 유지하는 것입니다. 이것은 일 것입니다.은 트랜잭션이 첫 번째 시도에서 올바른 데이터에서 실행되도록하고, 대역폭에 너무 많은 영향을 미치지 않으므로 (현재 값이 전송되어야하므로) 로컬 주소 대기 시간이 약간 증가합니다 (applyLocally이 설정된 경우). 또는 기본값은 true입니다. 나는 do thisNodeFire 라이브러리에, 다른 많은 최적화 및 개조 중.

위에 서술 한 바에 따르면,이 글을 쓰는 시점에서 SDK를 다시 시작하기 전까지 잘못된 기본 값이 "고정"되고 거래가 계속 재 시도 (maxretry 실패)하는 버그가 여전히 있습니다. 과정.

행운을 빈다. 나는 여전히 서버에서 실패를 재 시도 할 수있는 트랜잭션을 사용하고 여러 프로세스가 실행 중이지만 클라이언트에서이 프로세스를 사용하는 것을 포기했습니다. 이는 너무 신뢰할 수 없습니다. 제 생각에는 거래가 필요하지 않도록 데이터 구조를 재 설계하는 것이 더 나은 경우가 있습니다.

+0

나는 거래에 이런 문제가 있다는 것을 알지 못했습니다 ... +1. 트랜잭션을 필요로하지 않고이 "가치 증대"작업을 어떻게 재 설계 할 것을 제안 하시겠습니까? – qxz

+0

자세한 답변을 주셔서 대단히 감사합니다. 거래가 다소 망가져있는 것 같습니다. 클라이언트는 이러한 모든 고려 사항에 대해 걱정할 필요가 없습니다. 파이낸싱 거래를 사용하지 않고 은행 계좌 잔액을 모델링했다고 어떻게 제안 하시겠습니까? 트랜잭션을 사용하여 이것을 처리하는 강력한 방법이 없다면 나는 이것이 심각한 한계라고 느낀다. 또 다른 문제는 트랜잭션 적으로 일부 값을 업데이트하고 동시에 다른 위치를 원자 적으로 업데이트 할 수 있다는 것입니다. – user3391835

+0

하드 코어 게임에 중점을 둔이 모든 것은 힘든 경험이었습니다. 트랜잭션은 위의주의 사항을 염두에두면 간단한 증분으로도 괜찮습니다. 또 다른 접근법은 로그에 "+ N"항목을 넣고 서버가 주기적으로 트랜잭션을 롤업하도록하는 것입니다. 트랜잭션은 더 강력하고 궁극적으로 일관성이 있어야합니다. 클라이언트는 마지막 집계 값과 로그를 읽고 현재 값을 즉시 계산할 수 있습니다. 깊은 원자 업데이트는 가능하지만 트랜잭션 적이 될 수 없습니다. 다시, 로그 기반 디자인은 여러분의 친구입니다. – Piotr