2017-02-14 7 views
2

Мне нужны советы о том, как обрабатывать токен oauth2, обновляющийся в моем приложении.Предотвращение выполнения задач в одно и то же время

Я использую GRPC, чтобы сделать мои http-запросы к моему API, с которыми я связан с токеном oauth2 (он истекает через 1 час).

Перед началом каждого запроса, я проверяю маркер:

  • уточненный? запуск networkRequest

  • Устаревший? запуск refreshToken -> запустить networkRequest

Все, кажется, работает хорошо, но в некоторых случаях, мой клиент «потерять» маркер.

Проблема заключается в том, что для 2 запрашивает & B запущен в то же самое время, если маркер является устаревшим, они оба обновить его. Мой сервер будет генерировать newTokenA, вернуть его, сгенерировать newTokenB (удалить newTokenA), вернуть его. Если ответ newTokenA приходит к клиенту после newTokenB, токен токена клиента не будет хорошим.

Я использовал Семафор, чтобы обеспечить одновременный вызов refreshToken.

Но когда мой Семафор ждет, я не получаю никакого ответа от моего сервера.

let semaphore: dispatch_semaphore_t = dispatch_semaphore_create(0) 

func authenticate(completion: (GRPCProtoCall) -> (Void)) -> GRPCProtoCall { 

    // Wait here if authenticate already called 
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) 

    // If token up to date 
    if isOAuth2TokenValid() { 
     dispatch_semaphore_signal(semaphore) // Release semaphore 
     completion(self.withAuthorization()) 
     return self 
    } 

    // Refresh the outdated token 
    APIClient.shared.oAuth2AccessTokenRefresh { (response) -> (Void) in 
     dispatch_semaphore_signal(semaphore) // Release semaphore 
     completion(self.withAuthorization()) 
    } 

    return self 
} 
+0

Ведение очереди (может выполнять запросы последовательно) для маркеров отрады, как только кто-то приходит с новым запросом, если число больше, чем один в идеале вы уже Извлечение так что не обрабатывайте новый запрос. –

+0

Для чего это необходимо, инфраструктура https://github.com/p2/OAuth2 Swift сделает это за вас (раскрытие: я являюсь сторонником репо). – Pascal

ответ

1

Я думаю, что ваш dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) держит свой ю читать, вы можете попробовать его с тайм-аута упаковывают последний запрос не ответ, и поставить его перед Самовозврат

while semaphore.wait(timeout: DispatchTime.now() + Double(5000000000)/Double(NSEC_PER_SEC)) == DispatchTimeoutResult.success {//time out set to 5 seconds 
    print("wait") 
} 
+0

Спасибо за вашу помощь, семафор держал нить, и затем эта нить не могла получить никакого ответа от моего сервера! – Toldy

0

Во-первых, я хотел бы предложить создать семафор для 1 ресурса, а не для 0 (который используется для целей чтения):

let semaphore: dispatch_semaphore_t = dispatch_semaphore_create(0) 

Во-вторых, я думаю, что проблема в том, что вы первый релиз семафор, а затем вызвать блок завершения: Есть ли что-то вроде этого:

// Refresh the outdated token 
APIClient.shared.oAuth2AccessTokenRefresh { (response) -> (Void) in 
    completion(self.withAuthorization()) 
    dispatch_semaphore_signal(semaphore) // Release semaphore at very end 
} 
0

Почему бы не сделать метод полностью асинхронно? (self, кажется, известно, во всяком случае)

func authenticate(completion: (GRPCProtoCall) ->()) { 

    // If token up to date 
    if isOAuth2TokenValid() { 
     completion(self.withAuthorization()) 
    } else { 
    // Refresh the outdated token 
     APIClient.shared.oAuth2AccessTokenRefresh { response in 
      completion(self.withAuthorization()) 
     } 
    } 
}