Welcome to the Linux Foundation Forum!

Things about Ch7 lab1

krave
krave Posts: 58
edited March 2022 in LFW212 Class Forum

Finally passed all test in this lab. I'd like to share some points about this lab.

  1. The version of got used in our tutorials sticks with @11. Maybe the reason is that the latest version of got - version 12 was still under development when tutorials were under drafting. With version 11.8.3 , it seems that timeout option for got is not respected during the execution of my code. So I raised this issue on github. I tried timeout option in order to match this criteria:

Be sure that if an upstream service is not available, that the service responds within1250ms.

It seems that got will retry 3 times with 1000ms as interval by default.

The solution to bypass this criteria currently is to set retry to 0 .

Although this workaround helps me to pass the lab, but it is still not very doable in practice. Because retry of requests and controlling of the period of retry are very necessary in many scenarios.

  1. It looks like that the implemention of the validation will print all fastify log to the console. For example:

{"level":30,"time":1647899897407,"pid":15410,"hostname":"3855b2c37774","msg":"Server listening at http://0.0.0.0:3000"}
{"level":30,"time":1647899897677,"pid":15410,"hostname":"3855b2c37774","reqId":"req-1","req":> {"method":"GET","url":"/1","hostname":"localhost:3000","remoteAddress":"127.0.0.1","remotePort":58880},"msg":"incoming request"}
{"level":30,"time":1647899897700,"pid":15410,"hostname":"3855b2c37774","reqId":"req-1","res":{"statusCode":200},"responseTime":22.886099999770522,"msg":"request completed"}
☑️ GET http://localhost:3000/1 responded with 200 response

If you would like to hide these log, you can comment out the 81th line stdio: 'inherit',.

Comments

  • krave
    krave Posts: 58

    After digging into documents of got for a while, I noticed that timeout is used for the time got spends to wait for a response from a server. Due to the upstream service is not available at all, the bad response will be received by got in no time. So timeout option is not applicable in this scenario.

    Maybe you will ask, if response come back to got in no time, what causes the delay between got() invocation and error being caught.

    The answer is the retry mechanism of retry.
    You can find more details from here.

    Basically got will retry twice by default if error occurs when using got to send request. There will be a delay before each retry. There is an option retry.calculateDelay which determines the retry behavior of got. It is a function whose return valure will be the delay before each retry. If the return value is 0, then there will be no more retry and the promise returned by got() invocation will be rejected.

    There is also a algorithm to calculate the default delay of each retry.

    ((2 ** (attemptCount - 1)) * 1000) + noise

    That's why the total amount of time consumed by got until error being caught is around 3000 ms, which does not match our test criteria and leads to a test failure.

    I change the retry.calculateDelay from ({computedValue}) => computedValue to

    retry: {
          calculateDelay: () => {
            const current = performance.now()
            const delay = (current - start + retryInterval > mustThrowWithinThisPeriodIfAnyError) ? 0 : retryInterval
            console.log(current - start, mustThrowWithinThisPeriodIfAnyError, retryInterval);
            return delay
          }
        }
    

    current - start + retryInterval will let me know if I continue to next retry, whether the time consumed by this got() invocation will exceed the limitation set by the criteria of the lab. If not, then continue to next retry, otherwise return 0 from this function to canel next retry and end the retry behavior of got.

    The full version code of root route is

    'use strict'
    
    const got = require('got')
    
    const { BOAT_SERVICE_PORT, BRAND_SERVICE_PORT } = process.env
    
    module.exports = async function (fastify, opts) {
    
      const { notFound, badRequest } = fastify.httpErrors
    
      fastify.get('/:id', async function (request, reply) {
        const { id } = request.params
    
        try {
    
          const { brand: brandId, color } = await gotWrapper(BOAT_SERVICE_PORT, id, 1250, 500)
    
          const { name: brand } = await gotWrapper(BRAND_SERVICE_PORT, brandId, 1250, 500)
    
          return {
            id: Number(id),
            color,
            brand
          }
        } catch (err) {
          if (err.response) {
            if (err.response.statusCode === 404) {
              throw notFound()
            }
            if (err.response.statusCode === 400) {
              throw badRequest()
            }
    
            throw err
          }
          throw err
        }
    
      })
    }
    
    const gotWrapper = async (port, path, mustThrowWithinThisPeriodIfAnyError, retryInterval = 1000) => {
      const start = performance.now()
    
      return await got(`http://localhost:${port}/${path}`, {
        retry: {
          calculateDelay: () => {
            const current = performance.now()
            const delay = (current - start + retryInterval > mustThrowWithinThisPeriodIfAnyError) ? 0 : retryInterval
            console.log(current - start, mustThrowWithinThisPeriodIfAnyError, retryInterval);
            return delay
          }
        }
      }).json()
    }
    

    All tests will be passed meanwhile got will retry to send request in a relatively short period which is more realistic in our daily program.

  • xdxmxc
    xdxmxc Posts: 157

    excellent deep dive

  • Great deep dive,
    For this lab exercise, I had a simple solution, make the retry 0 and smaller timeout for got
    const gotOptions ={
    retry: {
    limit:0
    },
    timeout: {
    request: 50
    }
    }
    const boatRes = await got(${BOAT_URL}/${id}, gotOptions).json();

Categories

Upcoming Training