3

I am working on Windows Service in visual studio 2017. In the rest api's call, getting exceptions while debugging code. Sometimes first 2 3 calls working after that getting exceptions.

System.Net.WebException: 'The remote server returned an error: (503) Server Unavailable.'

The remote server returned an error: (429)

Unable to connect to the remote server

When calling same api's from Postman, getting response successfully.

This is my code

private void timer1_Tick(object sender, ElapsedEventArgs e)
{
    WriteToFile("timer1_Tick method called..");
try
{
    string jsonString = "";
    string jsonstring2 = "";
    string prodfetchurl = HOST;
    var req = WebRequest.Create(prodfetchurl) as HttpWebRequest;
    req.Method = "GET";
    InitializeRequest(req);
    req.Accept = MIME_TYPE;
    //System.Threading.Thread.Sleep(5000);
    var response = (HttpWebResponse)req.GetResponse();
    WriteToFile("First service called...");
    if (response.StatusCode == HttpStatusCode.OK)
    {
        Stream responseStream = response.GetResponseStream();
        StreamReader responseReader = new StreamReader(responseStream);
        jsonString = responseReader.ReadToEnd();
    }
    var deserialsseobj = JsonConvert.DeserializeObject<ProductList>(jsonString).Products.Where(i => i.Failed > 0).ToList();
    foreach (var a in deserialsseobj)
    {
        var pid = a.ID;
        string url = FailedDevicesUrl + pid.Value + "/failed";
        var req2 = WebRequest.Create(url) as HttpWebRequest;
        req2.Method = "GET";
        InitializeRequest(req2);

        req2.Timeout = 300000;
        req2.Accept = MIME_TYPE;
        var response1 = (HttpWebResponse)req2.GetResponse();
        Stream responsestream2 = response1.GetResponseStream();
        WriteToFile("Second service called...");
        if (response1.StatusCode == HttpStatusCode.OK)
        {
            StreamReader responsereader1 = new StreamReader(responsestream2);
            jsonstring2 = responsereader1.ReadToEnd();
        }

        var output = JsonConvert.DeserializeObject<List<FailedDeviceList>>(jsonstring2);  // Will get List of the Failed devices
        List<int> deviceids = new List<int>();
        Reprocessdata reproc = new Reprocessdata();
        Reprocessdata.DeviceId rprod = new Reprocessdata.DeviceId();

        reproc.ForceFlag = true;
        reproc.ProductID = pid.Value;
        foreach (var dd in output)
        {
            rprod.ID = dd.DeviceId;
            reproc.DeviceIds.Add(rprod);
        }

        // Reprocess the Product in Devices
        var req3 = WebRequest.Create(ReprocessUrl) as HttpWebRequest;
        req3.Method = "POST";
        InitializeRequest(req3);
        req3.Accept = MIME_TYPE;
        req3.Timeout = 300000;
        req3.ContentType = "application/json";
        using (StreamWriter writer = new StreamWriter(req3.GetRequestStream()))
        {
            string json = new JavaScriptSerializer().Serialize(reproc);

            writer.Write(json);
            writer.Close();
        }
        System.Threading.Thread.Sleep(5000);
        var response5 = (HttpWebResponse)req3.GetResponse();
        WriteToFile("Third service called...");
        if (response5.StatusCode == HttpStatusCode.OK)
        {
            string result;
            using (StreamReader rdr = new StreamReader(response5.GetResponseStream()))
            {
                result = rdr.ReadToEnd();
            }
        }
    }
    response.Close();
}
catch (Exception ex)
{
    WriteToFile("Simple Service Error on: {0} " + ex.Message + ex.StackTrace);
}
}

Methods used in above code

protected override void OnStart(string[] args)
{
    base.OnStart(args);
    timer1 = new System.Timers.Timer();
    timer1.Interval = 60000; //every 1 min
    timer1.Elapsed += new System.Timers.ElapsedEventHandler(timer1_Tick);
    timer1.Enabled = true;
    WriteToFile("Service has started..");
}

public void InitializeRequest(HttpWebRequest request)
{
    request.Headers.Add("aw-tenant-code", API_TENANT_CODE);
    request.Credentials = new NetworkCredential(USER_NAME, PASSWORD);
    request.KeepAlive = false;
    request.AddRange(1024);
}

When I contacted service provide they said everything fine from there side. Is this my code is buggy or windows service not reliable? How can I fix this issue?

Note: All APIS are working fine from Angular application using Visual Studio Code. It means my code is not working.

Edit1: Three below services I am using from this document of VMware.

private const string HOST = "https:host/api/mdm/products/search?";
private const string FailedDevicesUrl = "https:host/api/mdm/products/";
private const string ReprocessUrl = "https:host/api/mdm/products/reprocessProduct";
R15
  • 13,982
  • 14
  • 97
  • 173
  • Call more reliable service? – Alexei Levenkov Mar 04 '20 at 06:48
  • Are you saying, I should try using another services? I am using 3 services they are getting failed if 1st success 2nd will be failed if 1st and 2nd success 3rd will be fail. This way it is going on. rarely all 3 getting executed. – R15 Mar 04 '20 at 06:51
  • Yes, indeed if you don't want to receive 503 responses pick service that has better guarantees. Usually free services (or once that have TOU prohibiting such use outright) will try to do throttling or simply get overloaded resulting in 503. Calling your own well funded service or someone else payed service is solution to avoid 503... If for some reason you still want to call service that currently returns 503 you may want to chat with owners of the service and chip in to improve it... – Alexei Levenkov Mar 04 '20 at 07:01
  • These services are paid VMWare services I am using. While using Postman I am able to get response for the same service. but when it comes to my code that is not working. So I thought to put a question here by thinking that bug is in my code? – R15 Mar 04 '20 at 07:07
  • The question says that code works successfully - so there is not much to do in your client code - and instead either decrease load on server or ask to make server more performant or f you are hitting throttle limits and not real 503 ask owners to allow you to make more requests/more frequent requests. (I read "503 in 8 out of 10 cases" as 2 requests handled successfully implying that code constructs requests correctly, if that not the case - [edit] the question explaining if you are getting 40x or other 50x codes in remaining cases - that may be fixable client side) – Alexei Levenkov Mar 04 '20 at 07:16
  • Use KeepAlive, also use HTTP/2 if possible. – Akash Kava Mar 21 '20 at 06:18

2 Answers2

4

The inner error of that 503 is:

The remote server returned an error: (429)

HTTP 429 indicates too many requests. Maybe your upstream server can’t process all requests sent.

This can happen when you reached rate limiting / throttling value if you’re calling a third party API.

UPDATE

As per page 28 in the API docs, you could configure throttling when creating a new API. Check if the throttling is too small or maybe turn off the throttling and see if that could fix the error?

enter image description here

weichch
  • 9,306
  • 1
  • 13
  • 25
  • Is there any documentation that for 503 inner error is 429. – R15 Mar 19 '20 at 14:02
  • 503 and 429 are individual errors. 503s are usually from proxy servers, like a load balancer. It could be say the actual API server returned 429 to the load balancer, then gets wrapped with 503 and returned to client. – weichch Mar 19 '20 at 14:05
  • @ArvindChourasiya There might be throttling / quota configuration for your API, see page 28 of the API docs. Try increase throttling value or turn throttling off and see if that will fix the exception. – weichch Mar 20 '20 at 09:39
  • What is throttling configuration, how it will help me. – R15 Mar 20 '20 at 10:32
  • Throttling configuration is usually used to set the upper limit of how many API calls per minute or per day a server can accept. When exceeded, API should return HTTP 429 Too many requests indicating the scenario. And HTTP 429 is what you got as per the exception message. – weichch Mar 20 '20 at 10:36
  • Can I implement throttling programatically? – R15 Apr 01 '20 at 11:38
  • @ArvindChourasiya Throttling is something you might need to turn off or increase for diagnosing the error you had. If you have throttling enabled on server via the configuration, it is likely that during daily debugging / use the throttling value is hit and the server then starts returning 429 responses for a bit causing the error you got. Throttling may or may not be the real cause, but since the server has that, we have to eliminate the factor. – weichch Apr 01 '20 at 11:47
4

Response http code 429 indicates that you sending too many requests on target web service.

This means service you trying to send requests has a policies that blocks some requests by request-per-time limit.

Also I admit that external service can be manually configured to throw 403 code in specific cases that you can't know about. If that, this information can be explained in external service documentation... or not :)

What you can do with this?

Fit in limitations
You can make detailed research what limits target webservice has and set up your code to fit in this limitations. For example if service has limitation for receiving only one request per 10 minutes - you must set up your timer to send one request each 10 or more minutes. If documentation not provide such information - you can test it manually by finding some patterns with external service responses.

Use proxy
Every limitation policy based on information about requests senders. Usually this information consists of IP address of sender only. This means if you send 2 requests from two different IP addresses - limitation policy will perceive that like 2 different computers sending these requests. So you can find/buy/rent some proxy IP addresses and send requests through there on target web server.

How to connect through proxy in C# using WebRequest you can see in this answer.

Negotiate with external service provider
If you have possibility to communicate with external service developers or help center, you can ask their to reduce limitations for your IP address (if it static) or provide some mechanisms to avoid limitation policy for you. If for some reason they cannot provide this opportunity, at least you can ask detailed information about limitations.

Repetition mechanism
Some times 503 error code that is outer exception you received may be caused by service unavailable. It means that server can be under maintenance or temporary overloaded. So you can write repetition mechanism to make continious sending requests to server until it'll be accessible.

Polly library may help you with repetition mechanism creation

picolino
  • 4,856
  • 1
  • 18
  • 31
  • "can be manually configured to throw 403 code" - you probably mean 503? :) – janw Mar 19 '20 at 09:15
  • 1
    @JanWichelmann i mean every possible http response code that can be manually returned by server :) – picolino Mar 19 '20 at 09:21
  • @picolino - When I return back 10 mins of break and start debugging still getting 429(if I left it getting 429). Before every call I am having `Thread.Sleep(100000); ` still getting same issue, only first 1 or 2 calls working(if I press f10 if pressing f5 everything going in bg). Thank you. – R15 Mar 19 '20 at 13:58
  • @picolino Have you checked docs of the API provider, what is the threshold for request per *time*? – weichch Mar 19 '20 at 14:09
  • @ArvindChourasiya what external service API do you use? Is it open? Maybe we can help you with it's docs investigation? That error is really odd if you make 10 minutes breaks between requests. – picolino Mar 19 '20 at 14:18
  • @picolino - You can check my updated question in edit1. – R15 Mar 19 '20 at 14:32
  • @ArvindChourasiya I investigated documentation. Unfortunately there is no mentions about 429 error, but here what documentation says about 503 error: `This is used to indicate that the server is unable to handle the request due to temporary overload or maintenance of the service`. So I can't see some special conditions with it. I think you need to ask some help from developers of this service by clicking on [this link](https://support.workspaceone.com/) – picolino Mar 19 '20 at 16:40
  • @ArvindChourasiya also I've added into my answer another one solution that **might** be helpful for you. – picolino Mar 19 '20 at 16:41
  • @picolino - How can I use Polly library..Will it be really helpfull in this case. – R15 Mar 20 '20 at 11:55
  • @ArvindChourasiya you can set up retry policy to continiously send requests to target web service. See [detailed docs](https://github.com/App-vNext/Polly/wiki/Retry) for instructions how to do that. – picolino Mar 20 '20 at 11:59
  • @ArvindChourasiya about helpful... This solution will just make you requests sending repeatedly to server until one of them passed. So you need to make a choice, do you really want to solve this that way. – picolino Mar 20 '20 at 12:02