Faraday: Rety ๋ฏธ๋“ค์›จ์–ด๋Š” ํŒŒ์„œ ํ›„ ์‹คํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

์— ๋งŒ๋“  2021๋…„ 04์›” 23์ผ  ยท  4์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: lostisland/faraday

๊ธฐ๋ณธ ์ •๋ณด

  • ํŒจ๋Ÿฌ๋ฐ์ด ๋ฒ„์ „: 1.4.1
  • ๋ฃจ๋น„ ๋ฒ„์ „: 2.7.2

๋ฌธ์ œ ์„ค๋ช…

_NB: ๋Œ€์‹  faraday_middleware ์†ํ•˜๋Š”์ง€ ์•Œ๋ ค์ฃผ์„ธ์š”. ๋ฏธ๋“ค์›จ์–ด๊ฐ€ 2๊ฐœ๋‚˜ ๋“ค์–ด์žˆ์–ด์„œ ์–ด๋””์— ๋„ฃ์–ด์•ผ ํ• ์ง€ ๋ชฐ๋ž์–ด์š”._

์—ฐ๊ฒฐ์„ ์ƒ์„ฑํ•  ๋•Œ (๋ฌธ์„œํ™”๋œ ๋Œ€๋กœ) ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ์„ ์–ธ๋œ ์ˆœ์„œ๋Œ€๋กœ ์‹คํ–‰๋  ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์š”์ฒญ์ด ์‹คํŒจํ•˜๊ณ  :json ํŒŒ์‹ฑ โ€‹โ€‹๋ฏธ๋“ค์›จ์–ด ๋‹ค์Œ์— :retry ๋ฏธ๋“ค์›จ์–ด๋ฅผ ๋กœ๋“œํ•˜๋ฉด :retry ๋ฏธ๋“ค์›จ์–ด์˜ :retry_if ๋ฒ”์œ„์—์„œ env.body ๊ฐ€ ํŒŒ์‹ฑ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. :retry_if ๋ธ”๋ก:

JSON -decoded ๋ฉ”์‹œ์ง€์—์„œ :retry_if ๋ธ”๋ก์„ ์‹คํ–‰ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์š”์ฒญ์ด ์„ฑ๊ณตํ•˜๋ฉด JSON ๋ฌธ์„œ๊ฐ€ ๋งค์šฐ ์ปค์งˆ ์ˆ˜ ์žˆ๊ณ  ๋Œ€์•ˆ์€ retry_if , ์™„์ „ํžˆ ๋ถˆํ•„์š”ํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

์žฌํ˜„ ๋‹จ๊ณ„

<strong i="23">@_client</strong> ||= Faraday.new(url: ROOT_URL) do |f|
      f.options[:timeout] = 10
      f.headers['Content-Type'] = 'application/json'
      f.use :instrumentation, name: INSTRUMENTATION_EVENT_NAME
      f.response :json, content_type: /\bjson$/
      f.request :retry, FARADAY_RETRY_OPTIONS
end

์ฐธ๊ณ : ๋ธ”๋ก ๋‚ด๋ถ€์— f.instance_variable_get :@handlers ์ธ์‡„ํ•˜๋ฉด ์„ ์–ธํ•œ ์ˆœ์„œ๋Œ€๋กœ ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

์š”์ฒญ์ด ์‹คํŒจํ•˜๊ณ  :retry ๋ฏธ๋“ค์›จ์–ด์˜ :retry_if ๋ธ”๋ก์—์„œ ์ด๋Ÿฌํ•œ ํ‘œํ˜„์‹์„ ํ‰๊ฐ€ํ•˜๋ฉด ๋‹ค์Œ ์ถœ๋ ฅ์ด ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค.

(byebug) environment.response.to_hash.without(:url)
{:status=>405, :body=>"{\"message\": \"The method is not allowed for the requested URL.\"}\n", :response_headers=>{"date"=>"Fri, 23 Apr 2021 18:17:16 GMT", "content-type"=>"application/json", "content-length"=>"64", "connection"=>"keep-alive", "server"=>"gunicorn", "allow"=>"HEAD, OPTIONS, GET"}}

(byebug) environment.response.body
"{\"message\": \"The method is not allowed for the requested URL.\"}\n"
(byebug) environment.response.body.class
String

๊ธฐ๋ณธ์ ์œผ๋กœ ํŒŒ์‹ฑ ๋ฏธ๋“ค์›จ์–ด๋Š” ๋จผ์ € ์‹คํ–‰์„ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค.

JSON์ด ์ž˜ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๊ณ  ์‘๋‹ต์˜ Content-Type ํ—ค๋”๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋˜์–ด ์žˆ์–ด์„œ ๋‹นํ™ฉ์Šค๋Ÿฝ์Šต๋‹ˆ๋‹ค.

๋‚ด ์œ ์ผํ•œ ์ถ”์ธก์€ #response ๋ฏธ๋“ค์›จ์–ด๊ฐ€ ํ•ญ์ƒ #request ๋ฏธ๋“ค์›จ์–ด๋ณด๋‹ค ๋จผ์ € ์‹คํ–‰๋˜์ง€๋งŒ ์ด ๊ฒฝ์šฐ retry ๊ฐ€ #request ๋ฏธ๋“ค์›จ์–ด๋Š” ์ž˜๋ชป๋œ ๋ช…์นญ์ž…๋‹ˆ๋‹ค. ์‘๋‹ต์ด ๋ฐ˜ํ™˜๋œ ํ›„ ์•”์‹œ์ ์œผ๋กœ ํ‰๊ฐ€๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

์•ˆ๋…•ํ•˜์„ธ์š” @mvastola๋‹˜ , ์ง€๊ธˆ ๊ฒช๊ณ 
์ฒ˜์Œ์—๋Š” ๋จธ๋ฆฌ๋ฅผ ๊ตด๋ฆฌ๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ๋ฏธ๋“ค์›จ์–ด ์Šคํƒ์˜ ํŠน์„ฑ์ด ๋ž™ ์Šคํƒ๊ณผ ์œ ์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฏธ๋“ค์›จ์–ด๋Š” ์‘๋‹ต์„ ์œ„ํ•ด ์—ญ์ˆœ์œผ๋กœ ํŠธ๋ž˜๋ฒ„์Šค๋ฉ๋‹ˆ๋‹ค.
์šฐ๋ฆฌ ์›น ์‚ฌ์ดํŠธ ์—๋Š” ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋„๋ก ์ด๊ฒƒ์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ทธ๋ฆผ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋‹น์‹ ์€ ์ด๋ฏธ ์˜ณ์€ ์ผ์„ํ–ˆ์Šต๋‹ˆ๋‹ค ๐Ÿ™Œ! :json ๋ฏธ๋“ค์›จ์–ด๋ฅผ :retry ์ดํ›„๋กœ ์ด๋™ํ•˜๋ฉด ์‘๋‹ต์ด ๋จผ์ € ์ฒ˜๋ฆฌ๋˜๋„๋ก ํ—ˆ์šฉํ•˜๊ณ  :retry ๋ฏธ๋“ค์›จ์–ด๋Š” ๊ตฌ๋ฌธ ๋ถ„์„๋œ ์‘๋‹ต ๋ณธ๋ฌธ์„ ์ฐพ์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ ์ข…๋ฃŒํ•˜์ง€๋งŒ ์ถ”๊ฐ€ ์งˆ๋ฌธ์ด ์žˆ์œผ๋ฉด ์–ธ์ œ๋“ ์ง€ ๋ฌธ์˜ํ•ด ์ฃผ์„ธ์š”.

๋ชจ๋“  4 ๋Œ“๊ธ€

์—…๋ฐ์ดํŠธ: ๋ง ๊ทธ๋Œ€๋กœ ์—ฐ๊ฒฐ ๊ตฌ์„ฑ ๋ธ”๋ก์—์„œ ๋‘ ๋ฏธ๋“ค์›จ์–ด์˜ ์ˆœ์„œ๋ฅผ ๋’ค์ง‘์—ˆ๊ณ ("์ด๊ฒƒ์ด ์ž‘๋™ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค"๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด์„œ) ์ด์ œ ์™„๋ฒฝํ•˜๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”์ง€ ์ „ํ˜€ ๋ชจ๋ฅด๊ณ  ์—ฌ์ „ํžˆ ๋ฒ„๊ทธ์ฒ˜๋Ÿผ ๋ณด์ด๊ธฐ ๋•Œ๋ฌธ์—(๋˜๋Š” ์ ์–ด๋„ ๋” ์ž˜ ๋ฌธ์„œํ™”๋˜์–ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—) ์ด๊ฒƒ์„ ๋‚จ๊ฒจ๋‘ก๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” @mvastola๋‹˜ , ์ง€๊ธˆ ๊ฒช๊ณ 
์ฒ˜์Œ์—๋Š” ๋จธ๋ฆฌ๋ฅผ ๊ตด๋ฆฌ๊ธฐ๊ฐ€ ์–ด๋ ต๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ์ง€๋งŒ ๋ฏธ๋“ค์›จ์–ด ์Šคํƒ์˜ ํŠน์„ฑ์ด ๋ž™ ์Šคํƒ๊ณผ ์œ ์‚ฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฏธ๋“ค์›จ์–ด๋Š” ์‘๋‹ต์„ ์œ„ํ•ด ์—ญ์ˆœ์œผ๋กœ ํŠธ๋ž˜๋ฒ„์Šค๋ฉ๋‹ˆ๋‹ค.
์šฐ๋ฆฌ ์›น ์‚ฌ์ดํŠธ ์—๋Š” ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋„๋ก ์ด๊ฒƒ์„ ๋ณด์—ฌ์ฃผ๋Š” ๊ทธ๋ฆผ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋Ÿฌ๋ฏ€๋กœ ๋‹น์‹ ์€ ์ด๋ฏธ ์˜ณ์€ ์ผ์„ํ–ˆ์Šต๋‹ˆ๋‹ค ๐Ÿ™Œ! :json ๋ฏธ๋“ค์›จ์–ด๋ฅผ :retry ์ดํ›„๋กœ ์ด๋™ํ•˜๋ฉด ์‘๋‹ต์ด ๋จผ์ € ์ฒ˜๋ฆฌ๋˜๋„๋ก ํ—ˆ์šฉํ•˜๊ณ  :retry ๋ฏธ๋“ค์›จ์–ด๋Š” ๊ตฌ๋ฌธ ๋ถ„์„๋œ ์‘๋‹ต ๋ณธ๋ฌธ์„ ์ฐพ์Šต๋‹ˆ๋‹ค.

์ง€๊ธˆ ์ข…๋ฃŒํ•˜์ง€๋งŒ ์ถ”๊ฐ€ ์งˆ๋ฌธ์ด ์žˆ์œผ๋ฉด ์–ธ์ œ๋“ ์ง€ ๋ฌธ์˜ํ•ด ์ฃผ์„ธ์š”.

๋น ๋ฅด๊ณ  ์นœ์ ˆํ•˜๊ณ  ์ž์„ธํ•˜๊ฒŒ ์„ค๋ช…ํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ต์ง€๋Š” ์•Š์ง€๋งŒ ์—ฌ๊ธฐ์—์„œ๋Š” ์•ฝ๊ฐ„ ์ง๊ด€์ ์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํšจ๊ณผ์ ์œผ๋กœ ์ค„์ผ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์„œ

๋‚˜๋Š” ๋‹น์‹ ์ด ๋งํฌํ•œ ๋ฌธ์„œ๋ฅผ ์‹ค์ œ๋กœ ๋ณด์•˜๊ณ , ๋‚ด๊ฐ€ ํ•ด์•ผ ํ•  ์ผ์„ ์•Œ๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. (๋‚˜๋Š” ๊ทธ๋ฆผ๊ณผ "๊ฐ€์žฅ ์•ˆ์ชฝ์— ์žˆ๋Š”" ๋ฏธ๋“ค์›จ์–ด์— ๋Œ€ํ•œ ๋‚ด์šฉ์„ ๋ณด์•˜์ง€๋งŒ ๊ทธ๊ฒƒ์ด ์ˆœ์„œ๋ฅผ ๋ฐ˜๋Œ€๋กœ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค๊ณ  ์‹ค์ œ๋กœ ์ฒ˜๋ฆฌํ•˜์ง€๋Š” ์•Š์•˜์Šต๋‹ˆ๋‹ค.)

ํ‘œ์‹œ๋œ ์ด๋ฏธ์ง€๋Š” ๋ฏธ๋“ค์›จ์–ด์˜ ๋‚ด๋ถ€์™€ ๊ด€๋ จํ•˜์—ฌ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜์ง€๋งŒ ๊ตฌ์„ฑ ๋ธ”๋ก์˜ ์ˆœ์„œ๊ฐ€ ์‹คํ–‰ ์ˆœ์„œ์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ์„ ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œ์‹œํ•˜์—ฌ ์ด๋ฅผ ๋ณด์™„ํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ตฌ์„ฑ

๊ทธ ์™ธ์—๋„ ์ง๊ด€์ ์ด์ง€ ์•Š๊ฒŒ ๋งŒ๋“œ๋Š” ์ด ๊ตฌํ˜„์˜ ์„ธ๋ถ€ ์‚ฌํ•ญ์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • faraday ์—๋Š” ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•œ ์„ธ ๊ฐ€์ง€ ๋‹ค๋ฅธ ๊ธฐ๋Šฅ์ด ์žˆ์œผ๋ฉฐ ์ƒํ˜ธ ๊ตํ™˜ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ๊ฐ ๋ฏธ๋“ค์›จ์–ด๋Š” ๊ทธ ์ค‘ ํ•˜๋‚˜๋งŒ ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋งˆ์น˜ ์„œ๋กœ ๋…๋ฆฝ์ ์ธ 3๊ฐœ์˜ ์„œ๋กœ ๋‹ค๋ฅธ ๋ฏธ๋“ค์›จ์–ด ์Šคํƒ(๋˜๋Š” ์ˆœ์„œ ์ง€์ •)์ด ์žˆ๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ด๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

  • ๋ฏธ๋“ค์›จ์–ด์˜ ์ด ์„ธ ๊ฐ€์ง€ ๋‹ค๋ฅธ ์ด๋ฆ„/๊ทธ๋ฃน์ด ํ•˜๋Š” ์ผ์€ ๋งค์šฐ ๋ถˆ๋ถ„๋ช…ํ•˜์ง€๋งŒ ๋Œ€๋ถ€๋ถ„์˜ ๋ฏธ๋“ค์›จ์–ด๋Š” ์š”์ฒญ->์‘๋‹ต ๊ฒฝ๋กœ์˜ ์–‘์ชฝ ๋์—์„œ ์‹คํ–‰๋˜์ง€ _์•Š๊ธฐ_ ๋•Œ๋ฌธ์— ์‚ฌ์šฉ์ž๋Š” "์š”์ฒญ" ์ž‘์—…์ด ํ•ญ์ƒ "์‘๋‹ต"๋ณด๋‹ค ๋จผ์ € ๋ฐœ์ƒํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜๋Š” ๊ฒฝํ–ฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ด€๋ จ๋œ ๊ฒƒ๋“ค.

  • ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” rack ํ‚ค์›Œ๋“œ use ๋Š” ํŒจ๋Ÿฌ๋ฐ์ด์—์„œ ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ๋ชจ๋‘ ๊ฐ์‹ธ๋Š” ๋ฏธ๋“ค์›จ์–ด์ธ ๋ฏธ๋“ค์›จ์–ด์—๋งŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.

์–ด์จŒ๋“  ์ด ๋ฌธ์ œ์— ๋Œ€ํ•ด API๋ฅผ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ ๋ช‡ ๊ฐ€์ง€ ์•„์ด๋””์–ด๋ฅผ ์ƒ๊ฐํ•ด ๋ณผ ์ˆ˜ ์žˆ์–ด ๊ธฐ์ฉ๋‹ˆ๋‹ค. ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์ ์–ด๋„ ๋‚˜๋Š” ์ง€๊ธˆ ์ด๊ฒƒ์„ ์–ป์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—์„œ ๊ฐ™์€ ํ˜ผ๋ž€์„ ๊ฒช๊ณ ์žˆ๋Š” ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๋ฅผ ์‰ฝ๊ฒŒ ๋ณผ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—์ด ๋ง์„ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@mvastola ๊ฐ์‚ฌ
๊ทธ๋ฆฌ๊ณ  ๊ณต์ •ํ•˜๊ฒŒ ๋งํ•ด์„œ, ๋‚˜๋Š” ์ด๊ฒƒ์— ๋Œ€ํ•ด ์ฒ˜์Œ ๋“ฃ๋Š” ๊ฒƒ์ด ์•„๋‹™๋‹ˆ๋‹ค.

๋ฌธ์„œํ™”์— ๊ด€ํ•ด์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์•„์ง ๋ฉ€์—ˆ๋‹ค๋Š” ๋ฐ ๋™์˜ํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐœ์„ ์„ ์œ„ํ•œ ๊ธฐ์—ฌ๋Š” ๋งค์šฐ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค(์‹ค์ œ๋กœ ์ด์— ๋Œ€ํ•œ ๋งค์šฐ ์ตœ๊ทผ ํ† ๋ก  ์Šค๋ ˆ๋“œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค!).

๊ตฌ์„ฑ์— ๋Œ€ํ•œ ์š”์ ๋„ ๋งค์šฐ ์œ ํšจํ•ฉ๋‹ˆ๋‹ค. request , response ๋ฐ use ๋ฉ”์„œ๋“œ ํ˜ผ๋™์ด ์—ฌ๋Ÿฌ ๋ฒˆ ๋ฐœ์ƒํ•˜์—ฌ ์‹ค์ œ๋กœ use ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ๋‹จ์ˆœํžˆ ์‚ญ์ œํ•˜๋Š” ๊ฒƒ์„ ๊ณ ๋ คํ•˜๊ณ  ๋ฏธ๋“ค์›จ์–ด์— ๋‚จ๊ฒจ๋‘๊ณ  ์š”์ฒญ/์‘๋‹ต์„ ์กฐ์ž‘ํ•  ํ•ญ๋ชฉ/์‹œ๊ธฐ๋ฅผ ๋ฌธ์„œํ™”ํ•ฉ๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ์•„์ง๊นŒ์ง€๋Š” PR์„ ํ†ตํ•ด ํ•ด๋‹น API๋ฅผ ๋ณ€๊ฒฝํ•˜์ง€ ๋ง ๊ฒƒ์„ ์ œ์•ˆํ•˜์ง€๋งŒ ํ† ๋ก ์„ ํ†ตํ•ด ์ด ์ฃผ์ œ์— ๋Œ€ํ•œ ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ์˜๊ฒฌ์„ ๋“ค์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰