1

Bonjour et merci d'avance pour votre temps.Quelle est la bonne façon de travailler avec les objets AWSTask dans Swift?

Dans mon code, je fais diverses demandes à AWSSQS qui retournent toutes AWSTask. J'ai trouvé que travailler avec ces objets AWSTask était très difficile tout en essayant de garder toute la logique spécifique à AWS dans une seule classe afin de pouvoir facilement passer à un service de cloud différent si besoin est.

Idéalement, ce que je voudrais faire est d'exécuter une série de tâches AWS de manière asynchrone de manière sérielle. Normalement, je voudrais simplement ajouter des tâches à une file d'attente de répartition de série personnalisée, mais comme les objets AWSTask sont eux-mêmes des tâches asynchrones, je ne peux pas le faire.

Voici un exemple simple qui illustre le problème que j'ai. Il n'a pas de but réel, mais il illustre bien le problème. Ci-dessous, j'ai un code pour créer une file d'attente SQS, envoyer un message à une file d'attente SQS, recevoir un message d'une file d'attente SQS et supprimer une file d'attente SQS. Disons que je veux faire ces quatre choses de manière sérielle et asynchrone. En d'autres termes, je veux m'assurer que la tâche précédente a réussi avant d'essayer la tâche suivante.

ViewController

DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated).async { 
     awsClass.runTest() 
     DispatchQueue.main.async { 
      print("Test Finished") 
     } 
    } 

AwsClass

public func createQueue(){ 
    guard let createQueueRequest = AWSSQSCreateQueueRequest() else{fatalError()} 

    createQueueRequest.queueName = "TestQueue" 

    sqs.createQueue(createQueueRequest).continueWith(block: {(task) -> AnyObject? in 
     if task.error != nil { 
      print(task.error!) 
     } 
     else if task.result != nil { 
      self.queueUrl = task.result!.queueUrl! 
      print("created queue at: \(self.queueUrl!)") 
     } 
     return nil 
    }) 
} 

public func deleteQueue(){ 
    if queueUrl != nil { 
     guard let deleteQueueRequest = AWSSQSDeleteQueueRequest() else{fatalError()} 

     deleteQueueRequest.queueUrl = queueUrl 

     sqs.deleteQueue(deleteQueueRequest).continueWith(block: {(task) -> AnyObject? in 
      if task.error != nil { 
       print(task.error!) 
      } 
      else if task.result != nil { 
       print("queue sucessfully deleted from \(self.queueUrl!)") 
       self.queueUrl = nil 
      } 
      return nil 
     }) 
    } 
    else{ 
     print("Queue has already been deleted") 
    } 
} 

public func sendMessage(messageData: String, toConnectId: String) { 
    guard let sendMessageRequest = AWSSQSSendMessageRequest() else{fatalError()} 
    sendMessageRequest.queueUrl = toConnectId 
    sendMessageRequest.delaySeconds = 0 
    sendMessageRequest.messageBody = messageData 
    sqs.sendMessage(sendMessageRequest).continueWith(block: {(task) -> AnyObject? in 
     if task.error != nil { 
      print(task.error!) 
     } 
     else if task.result != nil { 
      print("successfully sent message to \(toConnectId)") 
     } 
     return nil 
    }) 
} 

public func receiveMessage(){ 
    guard let receiveMessageRequest = AWSSQSReceiveMessageRequest() else{fatalError()} 
    receiveMessageRequest.queueUrl = self.queueUrl 
    receiveMessageRequest.maxNumberOfMessages = 1 

    sqs.receiveMessage(receiveMessageRequest).continueWith(block: {(task) -> AnyObject? in 
     if task.error != nil { 
      print(task.error!) 
     } 
     else if task.result != nil { 
      let message = (task.result?.messages?.first)! 
      print("successfully received message with body: \(message.body ?? "failed")") 
     } 
     return nil 
    }) 
} 

public func runTest(){ 
    let mySerialQueue = DispatchQueue(label: "mySerialQueue") 
    mySerialQueue.sync { 
     self.createQueue() 
    } 
    mySerialQueue.sync { 
     self.sendMessage(messageData: "test", toConnectId: "https://someUrl") 
    } 
    mySerialQueue.sync { 
     self.receiveMessage() 
    } 
    mySerialQueue.sync { 
     self.deleteQueue() 
    } 
} 

Depuis les AWSTasks sont asynchrones avec des fonctions d'achèvement, le code fait rapidement tous les quatre appels, puis les fonctions d'achèvement sont appelés à chaque fois que terminent ces tâches. Au lieu de cela, je veux que la fonction d'achèvement de la première tâche se termine avant que la tâche suivante ne commence.

Répondre

0

Très bien, alors j'ai trouvé une solution à ma question. Il fonctionne exactement comme vous le souhaitez, mais il le fait dans cette mauvaise chaîne de fonctions d'achèvement. Si quelqu'un connaît une solution plus élégante, je suis tout ouïe!

ViewController

print("Starting Test") 
    DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated).async { 
     atomConnector.runTest(completion: { 
      print("test finshed") 
     }) 
    } 

AwsClass

public func createQueue(completion: @escaping() -> Void){ 
    guard let createQueueRequest = AWSSQSCreateQueueRequest() else{fatalError()} 

    createQueueRequest.queueName = "TestQueue" 

    sqs.createQueue(createQueueRequest).continueWith(block: {(task) -> Void in 
     if task.error != nil { 
      print(task.error!) 
     } 
     else if task.result != nil { 
      self.queueUrl = task.result!.queueUrl! 
      print("created queue at: \(self.queueUrl!)") 
      completion() 
     } 
    }) 
} 

public func deleteQueue(completion: @escaping() -> Void){ 
    if queueUrl != nil { 
     guard let deleteQueueRequest = AWSSQSDeleteQueueRequest() else{fatalError()} 

     deleteQueueRequest.queueUrl = queueUrl 

     sqs.deleteQueue(deleteQueueRequest).continueWith(block: {(task) -> Void in 
      if task.error != nil { 
       print(task.error!) 
      } 
      else if task.result != nil { 
       print("queue sucessfully deleted from \(self.queueUrl!)") 
       self.queueUrl = nil 
       completion() 
      } 
     }) 
    } 
    else{ 
     print("Queue has already been deleted") 
    } 
} 

public func sendMessage(messageData: String, toConnectId: String, completion: @escaping() -> Void) { 
    guard let sendMessageRequest = AWSSQSSendMessageRequest() else{fatalError()} 
    sendMessageRequest.queueUrl = toConnectId 
    sendMessageRequest.delaySeconds = 0 
    sendMessageRequest.messageBody = messageData 
    sqs.sendMessage(sendMessageRequest).continueWith(block: {(task) -> Void in 
     if task.error != nil { 
      print(task.error!) 
     } 
     else if task.result != nil { 
      print("successfully sent message to \(toConnectId)") 
      completion() 
     } 
    }) 
} 

public func receiveMessage(completion: @escaping() -> Void){ 
    guard let receiveMessageRequest = AWSSQSReceiveMessageRequest() else{fatalError()} 
    receiveMessageRequest.queueUrl = self.queueUrl 
    receiveMessageRequest.maxNumberOfMessages = 1 

    sqs.receiveMessage(receiveMessageRequest).continueWith(block: {(task) -> Void in 
     if task.error != nil { 
      print(task.error!) 
     } 
     else if task.result != nil { 
      let message = (task.result?.messages?.first)! 
      print("successfully received message with body: \(message.body ?? "failed")") 
      self.deleteMessage(receiptHandle: message.receiptHandle, completion: completion) 
     } 
    }) 
} 

public func deleteMessage(receiptHandle: String?, completion: @escaping() -> Void){ 
    guard let deleteMessageRequest = AWSSQSDeleteMessageRequest() else{fatalError()} 
    deleteMessageRequest.queueUrl = self.queueUrl 
    deleteMessageRequest.receiptHandle = receiptHandle 

    sqs.deleteMessage(deleteMessageRequest).continueWith(block: {(task) -> Void in 
     if task.error != nil { 
      print(task.error!) 
     } 
     else if task.result != nil { 
      print("successfully deleted message with receiptHandle: \(receiptHandle)") 
      completion() 
     } 
    }) 
} 

public func runTest(completion: @escaping() -> Void){ 

    self.createQueue(completion: { 
     self.sendMessage(messageData: "test", toConnectId: "https://someUrl", completion: { 
      self.receiveMessage(completion: { 
       self.deleteQueue(completion: { 
        completion() 
       }) 
      }) 
     }) 
    }) 

} 
1

Les objets AWSTask sont destinés à être "enchaîné" ensemble. La documentation se trouve ici: http://docs.aws.amazon.com/mobile/sdkforios/developerguide/awstask.html

Un petit exemple ici:

sqs.createQueue(/* parameters */).continueWithSuccess(block: {(task) -> Void in 
    // Success 
    return sqs.sendMessage(/* parameters */) 
}).continueWithSuccess(block: {(task) -> Void in 
    // Success 
    return sqs.receiveMessage(/* parameters */) 
}).continueWithSuccess(block: {(task) -> Void in 
    // Success 
    return sqs.deleteQueue(/* parameters */) 
})