axios: difference in timeout behavior between versions 0.18.1 and 0.19.0-2

Describe the bug

Using axios version 1.18.0, running the following mocha test, where the timeout is specified, results with:

Got the expected error:  timeout of 200ms exceeded
  ✓ test axios (210ms)

  1 passing (217ms)

Using axios version 1.19.x, running the same mocha test would result with

  1) test axios

  0 passing (1s)
  1 failing

  1) test axios:
     Error: drp. this happens instead
      at Timeout._onTimeout (src/subscriptions-manager/axios-test.js:24:14)
      at listOnTimeout (internal/timers.js:531:17)
      at processTimers (internal/timers.js:475:7)

To Reproduce run with mocha

const axios = require('axios');

const invalidUrl = 'http://12.12.12.12:123/arf/arf';

const postToInvalidUrl = async () => {

  return new Promise((resolve, reject) => {
    axios({
      url: invalidUrl,
      method: 'post',
      data: {not: 'relevant'},
      timeout: 200,
    })
      .then(() => {
        reject(new Error('success should"t happen'));
      })
      .catch(err => {
        console.log('Got the expected error: ', err.message);
        resolve();
      });

    setTimeout(function () {
      reject(new Error('drp. this happens instead'));
    }, 1000);
  });
};

it('test axios', async () => {
  await postToInvalidUrl();
});

Expected behavior that the behavior from 0.18.0 would be preserved

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 3
  • Comments: 25 (1 by maintainers)

Commits related to this issue

Most upvoted comments

Yes it is consistent for different values of timeout. However, the break in behavior seems to occur between 0.19.0 and 0.19.1 (i.e. the timeout value is respected for 0.19.0)

Hello All, I’ve spent few hours to know how timeouts are actually handled in both XHR and Node.js built-in HTTPClient.

Before starting a talk, I want to clarify variety types of timeouts.

In general, There are a lot of timeout types:

DNS Lookup Timeout

“DNS Lookup Timeout” indicates that client submitted the query to the DNS server, but didn’t get a response in specified time.

It usually occurs when the DNS server you queried was having a problem and couldn’t reply. Network errors could be another reason as well.

Connect Timeout

“Connect Timeout” indicates that client created socket and sent “TCP SYN” packet to server, but server dropped SYN packet and never replied SYN-ACK packet in specified time.

You can quickly reproduce “Connect Timeout” by connecting to non-routable destination like 10.255.255.1.

It usually occurs when server firewall drops SYN packets. Bad network connectivity could be another reason as well.

See also: http://willbryant.net/overriding_the_default_linux_kernel_20_second_tcp_socket_connect_timeout

Read Timeout

“Read Timeout” indicates that time of inactivity between two data packets when waiting for the server’s response exceeded specified time.

It usually occurs when server was super busy. Bad network condition could be another reason as well.

Write Timeout

“Write Timeout” indicates that time of inactivity between two data packets when sending the request to the server exceeded specified time.

It usually occurs when server was super busy. Bad network condition could be another reason as well.

Call Timeout

“Call Timeout” indicates that “complete” HTTP call didn’t completed in specified time. It includes entire timings from DNS Lookup to Response body download.

So many timeout types, right?

I wanted to know how platforms actually handle these timeouts. and here are what i’ve found during experiment: (you can see full experiment results from https://github.com/mooyoul/timeout-experiments)

  • timeout option in XHR defines “Call Timeout” which tracks entire HTTP call (from DNS Lookup to Response body download)
  • timeout option in http#request in Node.js defines “Idle timeout” which tracks “socket inactivity”
  • Currently, HTTPRequest#setTimeoutonly tracks “idle timeout”. which means “DNS Lookup timeout”, “Connect Timeout”, and “Call Timeout” cannot be limited or detected.

Luckily, In Node.js environment, Unsupported timeout types can be implemented from user-land (except connect timeout - it has a limitation of OS-wide setting). but In Browser environment, it cannot be implemented.

So the problem is what we should choose - Keep idiomatic timeout behavior, or Provide more timeout flexibility only in Node.js. I chose keeping idiomatic behavior. I am one of person who wants more timeout flexibility/options. but it makes axios difficult to maintain.

I’m not sure which way is the best - Please leave your thoughts!

So at this moment, I’m opening a PR that just reverts previous changes, with additional tests.

The timeout functionality breaks with https://github.com/axios/axios/pull/1752/files in axios v0.19.1

This is a pretty problematic bug. If URL is an IP address which is not reachable, the timeout will not be respected.