/// <summary> /// Periodically performs the following steps: /// 0. keep alive the session // 1. collect the freshest command bulk // 2. try-send bulk // 3. validate response // 4. parse response and enqueue for retry if needed // 5. wait for N seconds (N grows with the number of consecutive connection failures) /// </summary> /// <returns>The send loop enumerator.</returns> private IEnumerator APISendLoop(string target, PersistentBulkCommandQueue commandQueue) { const int WAIT_FOR_DEFAULT = 3; var httpTarget = target + Constants.BULK_URL; int consecutiveFailedRequests = 0; while (true) { // Decide if we process retry commands or new commands in this round List<object> commands = commandQueue.BulkDequeue(true); if (commands.Count > 0) { // 1B: Prepare the http components var httpBody = Json.Serialize(new Dictionary<string,object> {{"commands", commands}}); byte[] httpBodyBytes = Encoding.UTF8.GetBytes(httpBody); Dictionary<string,string> httpHeaders = new Dictionary<string,string>{ {"Content-type", "application/json"} }; // 2. Send the bulk API request WWW req = new WWW(httpTarget, httpBodyBytes, httpHeaders); //TODO: we could add a timeout functionality yield return req; // 3A: Check response for errors if (!string.IsNullOrEmpty(req.error)) { consecutiveFailedRequests++; } else { // 3B. Parse the API response var responseBody = req.text; Dictionary<string, object> apiResponse = (Dictionary<string, object>) Json.Deserialize(responseBody); bool success = (bool) apiResponse["success"]; if(success) { consecutiveFailedRequests = 0; // 4A: extract retry-commands and queue them back (if any) var retryCommands = ExtractRetryCommands(apiResponse,commands); commandQueue.MultiDequeue(commands.Count); //remove every command from this request commandQueue.MultiPush(retryCommands); //re-add failed commands with the highest priority } else { consecutiveFailedRequests++; } } } // 5. Detemine wait time and go idle. float waitSeconds = (float)System.Math.Pow(WAIT_FOR_DEFAULT, System.Math.Sqrt(consecutiveFailedRequests+1)); if(consecutiveFailedRequests == 0 && commandQueue.ElementCount > 0) { waitSeconds = 0f; } waitSeconds = System.Math.Min (waitSeconds, Constants.BULK_MAX - 3f); yield return new WaitForSeconds(waitSeconds); } }
public Sender(string target, PersistentBulkCommandQueue commandQueue) { this.StartCoroutine (APISendLoop(target, commandQueue)); }