๐Ÿ‘ท๐Ÿปโ€โ™‚๏ธ ์•Œ๋ฆผํ†ก ๊ฐœ์„ 

์„œ์žฌํ™˜ยท2022๋…„ 10์›” 17์ผ
0

Django

๋ชฉ๋ก ๋ณด๊ธฐ
31/40

์•Œ๋ฆผํ†ก ๊ฐœ์„ 

๐Ÿ“Œ ๊ธฐ๋Šฅ ์ •์˜

๋ฌธ์ œ์ 

  • ์ฑ„ํŒ…์„ ์ณค์„ ๋•Œ API๊ฐ€ ํ˜ธ์ถœ๋˜๋Š”๋ฐ ์˜ˆ์•ฝ๋‚ด์—ญ์— ์•Œ๋ฆผํ†ก์ด ์žˆ์„ ๋•Œ ์ด ์•Œ๋ฆผํ†ก์„ ์ทจ์†Œํ•˜๊ณ  ๋‹ค์‹œ ์˜ˆ์•ฝ์„ ๊ฑธ ๋•Œ ๊ธฐ์กด ์˜ˆ์•ฝ์‹œ๊ฐ„์œผ๋กœ ์˜ˆ์•ฝํ•˜์ง€ ์•Š๊ณ  ์˜ˆ์•ฝ์„ ๊ฑฐ๋Š” ์‹œ์ ์˜ ์‹œ๊ฐ„์„ ์˜ˆ์•ฝํ•˜๋Š” ๋ฌธ์ œ์ ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์ƒํ™ฉ

  • ๋ณดํ—˜์‚ฌ ์ง์› ์ฒ ์ˆ˜๊ฐ€ ์ฑ„ํŒ…๋ฐฉ์—์„œ ์˜ค์ „ 10์‹œ์— ์ฑ„ํŒ… ํ•˜๋‚˜๋ฅผ ์ „์†กํ–ˆ๋‹ค๊ฐ€ ์ž˜๋ชป ์ „์†กํ•œ ๊ฒƒ์„ ์ธ์ง€ํ•˜๊ณ  10์‹œ 01๋ถ„์ด ๋„๋ž˜ํ•˜๊ธฐ ์ „ 10์‹œ 00๋ถ„ 59์ดˆ์— ์ฑ„ํŒ…๋ฐฉ์— ์ฑ„ํŒ…์„ ์˜ฌ๋ฆฌ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์›๋ž˜ ํ•ด๋‹น ์•Œ๋ฆผํ†ก์€ 10์‹œ 1๋ถ„์— ๊ฐ€์ƒ๊ณต์—…์‚ฌ์— ์ „๋‹ฌ ๋  ์˜ˆ์ •์ด์—ˆ์œผ๋‚˜ ๋„๋ž˜ํ•˜๊ธฐ ์ „์— ์ฑ„ํŒ…์„ ์ „์†กํ•จ์œผ๋กœ์จ ๊ธฐ์กด์•Œ๋ฆผ์ด ์ทจ์†Œ ๋˜๊ณ  10์‹œ 01๋ถ„ 59์ดˆ ๋’ค์— ์•Œ๋ฆผ์ด ๊ฐ€๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋žฌ์„ ๋•Œ ์ฑ„ํŒ…๋ฐฉ์— ๊ณ„์† ์ฑ„ํŒ…์„ ์ƒ์„ฑํ•˜๊ฒŒ ๋  ๊ฒฝ์šฐ ์˜ˆ์ •๋œ ์‹œ๊ฐ„์— ์•Œ๋ฆผ์ด ๊ฐ€์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ์ ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ›  ์„ค๊ณ„ ๋ฐ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ

โš™๏ธ ์ถ”๊ฐ€๊ธฐ๋Šฅ

  • ๊ฐ€์ƒ ๊ณต์—…์‚ฌ๊ฐ€ ํ•˜๋‚˜์˜ ๋ฉ”์„ธ์ง€๋ฅผ ์ฝ์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ ํ•ด๋‹น ๋ฉ”์„ธ์ง€์˜ ๋‚ด์šฉ์ด ๋ณด์—ฌ์ง€๊ฒŒ ํ•œ๋‹ค.
  • ๊ฐ€์ƒ ๊ณต์—…์‚ฌ๊ฐ€ 2๊ฐœ ์ด์ƒ์˜ ๋ฉ”์„ธ์ง€๋ฅผ ์ฝ์ง€ ์•Š์•˜์„ ๊ฒฝ์šฐ ์ฝ์ง€ ์•Š์€ ๊ฑด์ˆ˜์— ๋Œ€ํ•ด์„œ ํ‘œ์‹œํ•˜๊ฒŒ ํ•œ๋‹ค.

โš™๏ธ ๋ชจ๋ธ๋ง

๐Ÿงฐ ๋„๊ตฌ ์„ ์ •

CoolSms

ํŠน์ • ์‹œ์ ์— ์›ํ•˜๋Š” ๊ธฐ๋Šฅ ์„ ์ˆ˜ํ–‰

  • ์œ„์— ์ ์–ด๋†“์€ ๋ถ€๋ถ„์ด 1์ฐจ์ ์œผ๋กœ ๊ฐ€์žฅ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค. CoolSms์— ๋ˆ์„ ๋‚ด๊ณ  ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์—ˆ๊ธฐ์— ๊ธฐ์กด์— ์žˆ๋Š” CoolSms๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํŠน์ • ์‹œ์ ์— ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด 1์ฐจ ์„ ํƒ์ง€๋ผ๊ณ  ์ƒ๊ฐ๋˜์–ด CoolSms์˜ ์˜ˆ์•ฝ ๊ด€๋ จ API๋ฅผ ์ด์šฉํ•˜์—ฌ ์œ„์˜ ๊ธฐ๋Šฅ ์„ ๊ตฌํ˜„ํ•˜๊ณ ์ž ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

  • CoolSms ๊ด€๋ จ ์ž๋ฃŒ ์ˆ˜์ง‘ ๊ฒฐ๊ณผ ์˜ˆ์•ฝ ์•Œ๋ฆผ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์กด์žฌํ–ˆ๊ณ  ํ•ด๋‹น ๊ธฐ๋Šฅ์€ ์–ธ์–ด๋ณ„๋กœ ์ฝ”๋“œ์™€ API๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์•„๋ž˜ ์ฝ”๋“œ๊ฐ€ ์˜ˆ์•ฝ๊ด€๋ จ๋œ ํŒŒ์ด์ฌ์ฝ”๋“œ ์ „๋ฌธ์ด์—ˆ๊ณ  ํ•ด๋‹น ์ฝ”๋“œ๋งŒ์œผ๋ก  sms ๊ธฐ๋Šฅ์— ๊ตญํ•œ๋œ๊ฑฐ์ง€, ์นด์นด์˜คํ†ก ์•Œ๋ฆผ๋„ ๊ฐ€๋Šฅํ•œ๊ฑฐ์ง€ ๊ฒ€์ฆํ•˜๋Š” ๊ณผ์ •์ด ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค.

if __name__ == '__main__':
    utc_offset_sec = time.altzone if time.localtime().tm_isdst else time.timezone
    utc_offset = datetime.timedelta(seconds=-utc_offset_sec)

    # ํฌ๋งํ•˜์‹œ๋Š” ์˜ˆ์•ฝ ๋‚ ์งœ๋ฅผ ๋„ฃ์–ด์ฃผ์„ธ์š”
    # datetime(๋…„, ์›”, ์ผ, ์‹œ, ๋ถ„, ์ดˆ)
    scheduledDate = datetime.datetime(2022, 2, 8, 0, 0, 0).replace(
        tzinfo=datetime.timezone(offset=utc_offset)).isoformat()
    data = {
        'scheduledDate': scheduledDate
    }

    # [INPUT_GROUP_ID] ์— ๊ทธ๋ฃน ์•„์ด๋””๋ฅผ ๋„ฃ์–ด์ฃผ์„ธ์š”
    # ex) G4V20181005122748TESTTESTTESTTES
    res = message.post('/messages/v4/groups/[INPUT_GROUP_ID]/schedule', data=data)
  • ๊ฒ€์ฆ ๊ฒฐ๊ณผ ํŠน์ • ์‹œ์ ์— ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์—ˆ๊ณ  1์ฐจ ์„ ํƒ์ง€๋กœ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•˜๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์œ„ API์— ์–ด๋–ป๊ฒŒ data๋ฅผ ๋‹ด๋Š”์ง€ ๊ถ๊ธˆํ•˜์‹ค ์ˆ˜๋„ ์žˆ์œผ์‹ค ๊ฒƒ ๊ฐ™์•„์„œ ์•„๋ž˜ ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์†Œ๊ฐœํ•ด๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค. ์‹ค์งˆ์ ์œผ๋กœ ๋‚ด์šฉ์„ ๋‹ด์•„ ํŠน์ • ์‹œ๊ฐ„์— ์•Œ๋ฆผ์„ ๋ณด๋‚ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ ์œ„ API data์—๋Š” ์•„๋ž˜์˜ ํ˜•ํƒœ๊ฐ€ ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜๊ณ  messages ๊ฐ€ key๋กœ []ํ˜•ํƒœ์˜ ๊ฐ’์„ ๊ฐ–๊ณ  ์žˆ๋Š”๋ฐ 'scheduledDate': scheduledDate ํ•ด๋‹น ํ˜•ํƒœ๋ฅผ data ๋ถ€๋ฌธ์— ์ถ”๊ฐ€ํ•ด์„œ ๋„ฃ์–ด ์ฃผ์‹œ๋ฉด ์ €ํฌ๊ฐ€ 1์ฐจ์ ์œผ๋กœ ๋ชฉํ‘œํ–ˆ๋˜ ์›ํ•˜๋Š” ์‹œ๊ฐ„์— ์•Œ๋žŒ์„ ๋ณด๋‚ด๋Š” ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
data = {
	"scheduledDate": scheduledDate
    "messages": [
        {
            "to": params["phone"],
            "from": settings.SENDER,
            "kakaoOptions": {
                "pfId": "KA01PF220419030622998QL1fNO8mOEN",
                "templateId": "KA01TP22101204464856145zRAS7bWfv"
                if settings.SERVER_ENVIROMENT == "prod"
                else "KA01TP220721063111651MN94HDoefzd",
                "variables": {
                    "#{name}": params["name"],
                    "#{bookingDate}": params["date"],
                    "#{bookingTime}": params["time"],
                    "#{carNum}": params["car_number"],
                    "#{repairshopName}": params["agent_name"],
                    "#{repairshopLocation}": params["agent_location"],
                    "#{code}": cipher,
                },
            },
        },
    ]
}

CoolSms๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ๋งˆ์ฃผํ•œ ๊ฒƒ๋“ค

GrouID

๊ทธ๋ฃน ์•„์ด๋””์— ๋Œ€ํ•œ ๊ฐœ๋…์ด ๋ช…ํ™•ํ•˜์ง€ ์•Š์•„ ์ฐพ์•„๋ณธ ๊ฒฐ๊ณผ ๋ฉ”์„ธ์ง€๋ฅผ ๋ฐœ์†ก ํ•  ๋•Œ์˜ ํŠธ๋žœ์žญ์…˜์œผ๋กœ์„œ์˜ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋Œ€์ƒ์ด๊ณ  ์ด๋ฅผ ๋ฉ”์„ธ์ง€ ์ „์†ก > ์ „์†ก ๊ฒฐ๊ณผ๋กœ ๋“ค์–ด๊ฐ€ ์•„๋ž˜์™€ ๊ฐ™์ด ํ™•์ธํ•ด ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ํŠธ๋žœ์žญ์…˜์ด๋ž€ ์ˆ˜ํ–‰ํ•ด์•ผํ•  ๊ณผ์—…์ด ๊ณผ์—…1, ๊ณผ์—…2, ๊ณผ์—…3 .. ๊ณผ์—…100 ๊ฐ€ ์žˆ๊ณ  ์ด๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š”๋ฐ ์žˆ์–ด ๋ฌถ์Œ์œผ๋กœ ์ˆ˜ํ–‰ํ•˜์—ฌ ๋ฐ˜์˜ํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ž…๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด ์ฒฉ๋ณด์˜ํ™”์—์„œ ์„œ๋ฒ„์‹ค์— ์นจ์ž…ํ•ด ์ค‘์š”ํ•œ ์ž๋ฃŒ๋ฅผ ๋ฐ›์œผ๋ ค๊ณ  ํ•  ๋•Œ 99%๋กœ์—์„œ ์ „์› ๋Š๊ธฐ๋ฉด 99% ๋ฐ›์€๊ฒŒ ์•„๋‹ˆ๋ผ ์›์ ์ž…๋‹ˆ๋‹ค. ๋ฌถ์Œ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด์„œ json ํ˜•ํƒœ์˜ response๋ฅผ ๋ณด๋ฉด _id ํ•„๋“œ์— G4V20221018095137DS0WQ7OZWQ0IPHL ๊ฐ€ ์ ํ˜€์žˆ๋Š”๋ฐ ํ•ด๋‹น ๋ถ€๋ฌธ์ด ๊ทธ๋ฃน์•„์ด๋””์— ํ•ด๋‹นํ•˜๋Š” ๋ถ€๋ฌธ์ด๊ณ  ์—ฌ๋Ÿฌ๊ฐœ๋ฅผ ํด๋ฆญํ•ด ๋ณด๋ฉด ๊ฐ๊ฐ๋งˆ๋‹ค ์„œ๋กœ ๋‹ค๋ฅธ ๊ทธ๋ฃน์•„์ด๋””๋กœ ๋ฉ”์„ธ์ง€๊ฐ€ ๊ด€๋ฆฌ๋˜๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰ ๋ฉ”์„ธ์ง€๋งˆ๋‹ค ๊ณ ์œ ํ•œ ๊ทธ๋ฃน์•„์ด๋””๊ฐ€ ๋ถ€์—ฌ๋˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

{
  "_id": "G4V20221018095137DS0WQ7OZWQ0IPHL",
  "count": {
    "total": 1,
    "sentTotal": 1,
    "sentFailed": 0,
    "sentSuccess": 1,
    "sentPending": 0,
    "sentReplacement": 0,
    "refund": 0,
    "registeredFailed": 0,
    "registeredSuccess": 1
  },
  "countForCharge": {
    "sms": {},
    "lms": {
      "82": 1
    },
    "mms": {},
    "ata": {},
    "cta": {},
    "cti": {},
    "nsa": {},
    "rcs_sms": {},
    "rcs_lms": {},
    "rcs_mms": {},
    "rcs_tpl": {}
  },
  "balance": {
    "requested": 0,
    "replacement": 0,
    "refund": 0,
    "sum": 0
  },
  "point": {
    "requested": 50,
    "replacement": 0,
    "refund": 0,
    "sum": 50
  },
  "app": {
    "profit": {
      "sms": 0,
      "lms": 0,
      "mms": 0,
      "ata": 0,
      "cta": 0,
      "cti": 0,
      "nsa": 0,
      "rcs_sms": 0,
      "rcs_lms": 0,
      "rcs_mms": 0,
      "rcs_tpl": 0
    },
    "appId": null,
    "version": null
  },
  "serviceMethod": "MT",
  "sdkVersion": "sms-python 2.0.3",
  "osPlatform": "14.38.93.171|Darwin|Python 3.9.4|sms/2",
  "log": [
    {
      "createAt": "2022-10-18T00:51:37.200Z",
      "message": "[::ffff:127.0.0.6] ๋ฉ”์‹œ์ง€ ๊ทธ๋ฃน์ด ์ƒ์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
    },
    {
      "createAt": "2022-10-18T00:51:37.265Z",
      "message": "๊ตญ๊ฐ€์ฝ”๋“œ(82)์˜ ์žฅ๋ฌธ๋ฌธ์ž(LMS) 1 ๊ฑด์ด ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค."
    },
    {
      "createAt": "2022-10-18T00:51:37.422Z",
      "message": "๋ฉ”์‹œ์ง€๋ฅผ ๋ฐœ์†กํ–ˆ์Šต๋‹ˆ๋‹ค.",
      "oldBalance": 0,
      "newBalance": 0,
      "oldPoint": 74489,
      "newPoint": 74439,
      "totalPrice": 50
    }
  ],
  "status": "COMPLETE",
  "dateSent": "2022-10-18T00:51:37.422Z",
  "scheduledDate": null,
  "dateCompleted": "2022-10-18T00:51:50.855Z",
  "isRefunded": false,
  "flagUpdated": false,
  "prepaid": true,
  "strict": false,
  "masterAccountId": null,
  "allowDuplicates": false,
  "accountId": "21030220742796",
  "apiVersion": "2",
  "customFields": {
    "coolsmsGroupId": "R2Gx2hrUE7Ppm84k"
  },
  "hint": null,
  "groupId": "G4V20221018095137DS0WQ7OZWQ0IPHL",
  "price": {
    "82": {
      "sms": 20,
      "lms": 50,
      "mms": 120,
      "ata": 13,
      "cta": 19,
      "cti": 26,
      "nsa": 13,
      "rcs_lms": 40,
      "rcs_mms": 75,
      "rcs_sms": 15,
      "rcs_tpl": 12
    }
  },
  "dateCreated": "2022-10-18T00:51:37.202Z",
  "dateUpdated": "2022-10-18T00:51:50.855Z"
}

์˜ˆ์•ฝ ์ทจ์†Œ

import json
from src.lib import message

'''
์˜ˆ์•ฝ ๋ฐœ์†ก ์ทจ์†Œ ์˜ˆ์ œ, ์ด๋ฏธ ์˜ˆ์•ฝ ๋ฐœ์†ก์ด ์„ค์ •๋˜์–ด ์žˆ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. 
'''
if __name__ == '__main__':
    # [INPUT_GROUP_ID] ์— ๊ทธ๋ฃน ์•„์ด๋””๋ฅผ ๋„ฃ์–ด์ฃผ์„ธ์š”
    # ex) G4V20181005122748TESTTESTTESTTES
    res = message.delete('/messages/v4/groups/[INPUT_GROUP_ID]/schedule', data=None)
    print(json.dumps(json.loads(res.text), indent=2, ensure_ascii=False))
  • ์˜ˆ์•ฝ ์ทจ์†Œ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด [INPUT_GROUP_ID]์— ๊ทธ๋ฃน์•„์ด๋””๋ฅผ ๋„ฃ์–ด์„œ ๊ธฐ์กด ์ง„ํ–‰ํ–ˆ๋˜ ์˜ˆ์•ฝ์„ ์ทจ์†Œํ•˜์‹œ๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์˜ˆ์•ฝ์„ ๊ฑธ๊ณ  ์ทจ์†Œํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„  1)API์š”์ฒญ์„ ํ†ตํ•ด ๊ทธ๋ฃน์•„์ด๋””๋ฅผ ๋ฐœ๊ธ‰๋ฐ›๊ณ  ์ด๋ฅผ ๊ด€๋ฆฌํ•˜์—ฌ ์˜ˆ์•ฝ API ๋˜๋Š”์˜ˆ์•ฝ ์ทจ์†Œ API๋ฅผ ํ˜ธ์ถœํ•ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐฉํ–ฅ์„ฑ

์ €ํฌ๊ฐ€ ํ•„์š”๋กœ ํ–ˆ๋˜ ๊ธฐ๋Šฅ, 1) ์›ํ•˜๋Š” ์‹œ๊ฐ„์— ์˜ˆ์•ฝ์„ ํ•˜๋Š” ๊ธฐ๋Šฅ, 2) ๊ธฐ์กด ์˜ˆ์•ฝ์„ ์ทจ์†Œํ•˜๋Š” ๊ธฐ๋Šฅ 2๊ฐ€์ง€ ๋ชจ๋‘ ์ถฉ์กฑํ•˜๊ณ  ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์— CoolSms๋ฅผ ํ™œ์šฉํ•œ 1์ฐจ ๊ฐœ๋ฐœ์„ ์™„๋ฃŒํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฌธ์ œ์ , GroupID์˜ ์žฆ์€ ๋ฐœ๊ธ‰์œผ๋กœ ์ธํ•œ ๋กœ๊ทธ ํ™•์ธ์˜ ์–ด๋ ค์›€

์›ํ•˜๋Š” ๊ธฐ๋Šฅ์˜ API๋ฅผ ์ œ๊ณตํ–ˆ๊ธฐ์— ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ์—ˆ์œผ๋‚˜ ํ•ด๋‹น API๋Š” ๋ˆ„๊ตฐ๊ฐ€๊ฐ€ ์ฑ„ํŒ…์„ ์ณค์„ ๋•Œ ๋™์ž‘ํ•˜๋Š” API๋กœ ์ฑ„ํŒ… ์ „์†ก์ด ๋ฐฉ์•„์‡  ์—ญํ• ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” API๊ฐ€ ์žฆ๊ฒŒ ํ˜ธ์ถœ ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ๋งŒ์ผ ์—ฌ๋Ÿฌ ์ฑ„ํŒ…๋ฐฉ์—์„œ ์—ฌ๋Ÿฌ ๊ฑด์˜ ์ฑ„ํŒ…์ด ์ƒ์„ฑ ๋  ๊ฒฝ์šฐ ์˜ˆ์•ฝ ๊ด€๋ จํ•ด์„œ ๋‹ด๋‹นํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์—ฌ๋Ÿฌ๋ฒˆ ํ˜ธ์ถœ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•˜๊ณ  ์ด๋Š” ๊ณ„์†ํ•ด์„œ ๊ทธ๋ฃน์•„์ด๋””๋ฅผ ๋ฐœ๊ธ‰ ๋ฐ›์•„์•ผ ํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋‚ณ๊ณ  CoolSmS ํ™ˆํŽ˜์ด์ง€ ๋ฉ”์„ธ์ง€ ๋กœ๊ทธ์— ์ •์ƒ ๋ฐœ์†ก๊ฑด๊ณผ ํ˜ผ์žฌ๋˜๋ฉด์„œ ํ™•์ธํ•˜๋Š”๋ฐ ์–ด๋ ค์›€์„ ์ดˆ๋ž˜ํ•ฉ๋‹ˆ๋‹ค.

ํ˜„์žฌ Backend์—์„œ ํ˜ธ์ถœ๋˜๊ณ  ์žˆ๋Š” API

path(
    "chat/<int:parts_req_id>/create/<int:match_id>",
    views.MatchChatCreateView.as_view(),
    name="match_chat_create_view",
)

CoolSms Log ๋‚ด์—ญ

๐Ÿงฐ ๋„๊ตฌ ์žฌ์„ ์ •

์„ ํƒ์˜ ์–ด๋ ค์›€

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

๋‚ด์žฅ ๋ชจ๋“ˆ

ํŒŒ์ด์ฌ์—์„  ์‹œ๊ฐ„์„ ์กฐ์ž‘ํ•˜๋Š” time, threading ๋ชจ๋“ˆ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ํ•ด๋‹น ๋ชจ๋“ˆ์„ ์‚ฌ์šฉ ํ•  ๊ฒฝ์šฐ ์ฃผ๊ธฐ์ ์œผ๋กœ ์›ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์›ํ•˜๋Š” ์‹œ๊ฐ„๋Œ€์— ํŠน์ • ๊ธฐ๋Šฅ์„ ํ™œ์„ฑํ™”์‹œํ‚ค๊ธฐ ์œ„ํ•œ ๋‹จ์„œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

sched

์™ธ๋ถ€ ๋ชจ๋“ˆ์ธ sched ๋˜ํ•œ ๋‚ด์žฅ๋ชจ๋“ˆ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ €ํฌ๊ฐ€ ์›ํ•˜๋Š” ์‹œ๊ฐ„์— ํŠน์ • ๊ธฐ๋Šฅ์„ ํ•œ๋ฒˆ ํ˜ธ์ถœํ•˜๊ธฐ ์œ„ํ•œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ๋‹จ์„œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

django-apscheduler, Celery

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

๊ทธ๋ ‡๋‹ค๋ฉด ์ €ํฌ๊ฐ€ ํ•ด๊ฒฐํ•˜๊ณ  ์‹ถ์€ ๋ถ€๋ถ„ -:> ์›ํ•˜๋Š” ์‹œ๊ฐ„์— ์˜ˆ์•ฝ์„ ๊ฑธ๊ณ  ์ทจ์†Œ ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์žˆ๋Š”์ง€ ํŒŒ์•…ํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฑ„ํŒ…์„ ์น˜๋Š” ํ–‰์œ„ ์ž์ฒด๊ฐ€ ์ฃผ๊ธฐ์ ์ธ ์„ฑ๊ฒฉ์„ ๋„์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ํ˜„์žฌ ๋ฐฑ์—”๋“œ ์ชฝ์—์„œ Celery์™€ django-apscheduler๊ฐ€ ์„ค์น˜๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ €์˜ ์ฒซ๋ฒˆ์งธ ์„ ํƒ์€ django-apscheduler ์˜€์Šต๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์—ˆ๊ณ  ์กฐ๊ธˆ ๋” ํ™•์žฅํŒฉ ๋Š๋‚Œ์ธ Celery์˜ ๋„์ž…์€ ์ดํ›„์˜ ์ˆœ์œ„๋ผ๊ณ  ์ƒ๊ฐํ•˜์˜€๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‹คํ–‰ํžˆ ์›ํ•˜๋Š” ์‹œ๊ฐ„์— ์˜ˆ์•ฝ์„ ๊ฑธ๊ณ  ์ทจ์†Œ ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

django-apscheduler ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ 4๊ฐœ์˜ ๊ฐœ๋…

  • triggers
    ์–ธ์ œ ํŠน์ •ํ•œ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•  ์ง€๋ฅผ ์•Œ๋ ค์ฃผ๋Š” ์—ญํ• ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ดฌ์˜์žฅ์—์„œ ์Šฌ๋ ˆ์ดํŠธ์™€ ๊ฐ™์€ ์—ญํ• ์ด๋‹ค.

  • job stores
    ์–ธ์ œ ํŠน์ •ํ•œ ๊ธฐ๋Šฅ์„ ํ•˜๊ธฐ๋กœ ํ–ˆ๋Š”์ง€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ Jobs๋ฅผ ์ €์žฅํ•˜๊ณ  ์žˆ๋Š” ๊ณต๊ฐ„์ž…๋‹ˆ๋‹ค. ๊ธฐ๋ณธ ์ €์žฅ๊ณต๊ฐ„์„ ์‚ฌ์šฉ ํ•  ๊ฒฝ์šฐ memory๋กœ ๊ด€๋ฆฌ๋˜๊ณ  scheduler๋Š” ํ•ด๋‹น ๊ณต๊ฐ„์„ ์„œ๋กœ ๊ณต์œ ํ•˜์ง€ ์•Š๊ณ  ๋…๋ฆฝ์ ์œผ๋กœ ๊ฐ–๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • executors
    job store์— ์ €์žฅ๋œ Job ๋“ค์„ ์“ฐ๋ ˆ๋“œ ๋˜๋Š” ํ”„๋กœ์„ธ์Šค ํ’€์— ๋˜์ ธ์ฃผ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ฆ‰ ์ €์žฅ๊ณต๊ฐ„์— ์Œ“์ธ ์ผ๊ฐ๋“ค์ด ์‹คํ–‰๋˜์–ด์•ผ ํ•  ์‹œ์ ์ด ์™”์„ ๋•Œ ๋Œ€๊ธฐ์กฐ์— ์žˆ๋Š” ์ผ๊พผ๋“ค์—๊ฒŒ ์ผ์„ ์ „๋‹ฌ ํ•ด์ฃผ๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

  • schedulers
    ์œ„์˜ ์ž‘์—…๋“ค, Job์— ๋Œ€ํ•œ ํŠธ๋ฆฌ๊ฑฐ ์ง€์ •, Job์˜ ์ €์žฅ, Job์˜ ์‹คํ–‰๋“ฑ์„ ๊ด€์žฅํ•˜๋Š” ์—ญํ• ์„ ๋‹ด๋‹นํ•ฉ๋‹ˆ๋‹ค. ์ €์™€ ๊ฐ™์€ ์•ฑ๊ฐœ๋ฐœ์ž๋Š” schedulers๋ฅผ ํ†ตํ•ด ์œ„์˜ ์ฃผ์ฒด๋“ค๊ณผ ์†Œํ†ตํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์„ ์ • ๊ณผ์ •

์œ„์˜ 4๊ฐ€์ง€ ๊ฐœ์ฒด๋ฅผ ์„ ์ •ํ•˜๋Š” ์ž‘์—…์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์˜ˆ์ œ ์ฝ”๋“œ๊ฐ€ ์žˆ์–ด ์˜ˆ์ œ์ฝ”๋“œ๋ฅผ ํ†ตํ•ด ํ•ด๋‹น ๊ฐœ์ฒด๋“ค์„ ์ง€์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด ๋‚˜๊ฐ”์Šต๋‹ˆ๋‹ค.

scheduler ---> BackgroundScheduler

์Šค์ผ€์ค„๋Ÿฌ์˜ ๊ฒฝ์šฐ django-apscheduler๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ €ํฌ๋Š” ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ฑ„ํŒ…๋ฐฉ์ด ์ƒ์„ฑ ๋  ๊ฒฝ์šฐ ์ฑ„ํŒ…๋ฐฉ ๊ฐ๊ฐ์„ ๋‹ด๋‹นํ•˜๋Š” ๋…๋ฆฝ์ ์ธ scheduler๊ฐ€ ํ•„์š”ํ•˜๋ฏ€๋กœ BackgroundScheduler๋ฅผ ์„ ํƒํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๋ณดํ†ต ๋งŽ์ด ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

job store ---> MemoryJobStore

  • you need to determine whether you need job persistence or not

์‹คํ–‰ ํ•  ์ผ์„ ์ €์žฅ ํ• ์ง€ ๋ง์ง€๋ฅผ ๊ฒฐ์ •ํ•ด์•ผ ํ–ˆ๋Š”๋ฐ ์„ค๊ณ„ ํŠน์„ฑ์ƒ ์˜ˆ์•ฝ์ด ๊ฑธ๋ ค์žˆ๋Š”์ง€ ๊ฑธ๋ ค์žˆ์ง€ ์•Š์€์ง€๊ฐ€ ๋ถ„๊ธฐ์ ์ด ๋˜์–ด ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๋ฏ€๋กœ Memory์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” job ํ•˜๋‚˜๋งŒ ํ•„์š”ํ•˜๋ฏ€๋กœ ์ด ๋˜ํ•œ ๊ธฐ๋ณธ์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.

trigger --> date

ํŠธ๋ฆฌ๊ฑฐ์˜ ์ข…๋ฅ˜์—๋Š” 3๊ฐ€์ง€ ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์žˆ๋Š”๋ฐ date ํŠธ๋ฆฌ๊ฑฐ๊ฐ€ ์ €ํฌ์˜ ๋ชฉ์ ์ธ ํŠน์ • ์‹œ์ ์— ์›ํ•˜๋Š” ์žก์‹คํ–‰ ์˜ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ด์ฃผ๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๐Ÿคฉ

๐Ÿ’ก ์ด๋กœ์„œ ์•ž์œผ๋กœ์˜ ๊ฐœ๋ฐœ ๋ฐฉํ–ฅ์— ํฌ๋ง์ด ์ƒ๊ฒผ์Šต๋‹ˆ๋‹ค.

๐Ÿ›  Trouble Shooting

์„ค๊ณ„ ํ›„ ์„ ํƒํ•œ ๋„๊ตฌ๋ฅผ ํ†ตํ•ด์„œ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ–ˆ์„ ๋•Œ ๋งˆ์ฃผํ•œ ๋ฌธ์ œ์ ๋“ค์„ ๋‚˜์—ดํ•˜๊ณ  ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ•˜์˜€์ง€ ๊ทธ ๊ณผ์ •์— ๋Œ€ํ•ด์„œ ๋‚˜๋ˆ„๊ณ ์žํ•ฉ๋‹ˆ๋‹ค.

์Šค์ผ€์ค„ ๋ฉ”ํƒ€

์Šค์ผ€์ค„์„ ๋Œ๋ฆฌ๊ธฐ ์œ„ํ•ด์„  ์•„๋ž˜์˜ ์ˆœ์„œ๋ฅผ ๋”ฐ๋ผ์„œ ์žก์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์Šค์ผ€์ค„์„ ๋Œ๋ฆฐ ์ดํ›„์—๋Š” ์„ค์ • ๊ฐ’์„ ๋™์ ์œผ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
์Šค์ผ€์ค„๋Ÿฌ ์ƒ์„ฑ ---> ์‹คํ–‰ ํ•  ์žก ์ถ”๊ฐ€ ---> ์žก ์‹คํ–‰

scheduler = BackgroundScheduler()
scheduler.add_job(ํ•จ์ˆ˜, ํŠธ๋ฆฌ๊ฑฐ ์œ ํ˜•, ํŠธ๋ฆฌ๊ฑฐ ๊ฐ’, ํ•จ์ˆ˜์ธ์ž)
scheduler.start()

Scheduler ์ƒํƒœ

  • STATE_STOPPED(0)
  • STATE_RUNNING(1)
  • STATE_PAUSED(2)

Job ์ œ๊ฑฐ

Scheduler ๋ฎ์–ด์“ฐ๋Š” ๋ฌธ์ œ

ํ˜„์žฌ ํ˜ธ์ถœ๋˜๊ณ  ์žˆ๋Š” APIํ˜•ํƒœ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. API๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ๋งˆ๋‹ค MatchChatCreateView๋ผ๋Š” ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งค๋ฒˆ ์ƒ์„ฑ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ฑ„ํŒ…๋ฐฉ์—์„œ ์ฑ„ํŒ…์ด ์˜ฌ๋ผ์˜ค๊ฒŒ ๋  ๊ฒฝ์šฐ ํ•ด๋‹น ํด๋ž˜์Šค๋กœ๋ถ€ํ„ฐ ์ƒˆ๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์˜ˆ์ƒ ์ž‘๋™ ๋กœ์ง์˜ ๊ฒฝ์šฐ ๊ฐ๊ฐ์˜ ์ฑ„ํŒ…๋ฐฉ๋งˆ๋‹ค ํ•˜๋‚˜์˜ ์Šค์ผ€์ค„๋Ÿฌ ์ธ์Šคํ„ด์Šค๋ฅผ ๊ณ„์†ํ•ด์„œ ์‚ฌ์šฉํ•ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

๋งŒ์•ฝ ์ด์ „์— ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ๋งŒ๋“  ๊ฒƒ์„ ๊ธฐ์–ตํ•˜์ง€ ๋ชปํ•œ๋‹ค๋ฉด ์—ฌ๋Ÿฌ๊ฐœ์˜ ์ฑ„ํŒ… ๋ฐฉ์—์„œ ์ฑ„ํŒ…์ด ์˜ฌ๋ผ์˜ฌ ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋‚ณ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๋”ฐ๋ผ์„œ ํ•ด๋‹น API๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ์ฑ„ํŒ…๋ฐฉ๋งˆ๋‹ค ๊ณ ์œ ์˜ ์Šค์ผ€์ค„๋Ÿฌ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งค์นญํ•ด์ฃผ๊ธฐ ์œ„ํ•ด์„  ์ฑ„ํŒ…๋ฐฉ์˜ ๊ณ ์œ ์•„์ด๋””๋ฅผ ์ƒ์„ฑ์ž ๋ณ€์ˆ˜๋กœ ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์•„๋ฌด๋ฆฌ ๋งŽ์€ API๊ฐ€ ํ˜ธ์ถœ๋˜๋”๋ผ๋„ ์ฑ„ํŒ…๋ฐฉ ๋ณ„๋กœ ์˜ค์ง ํ•˜๋‚˜์˜ ์Šค์ผ€์ค„๋Ÿฌ๋งŒ ์ƒ์„ฑํ•˜๊ฒŒ ์กฐ์ •ํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š” ์ž‘์—…์ด ํ•„์š”ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์— ํด๋ž˜์Šค ๋ณ€์ˆ˜๋ฅผ ๋‘๊ณ  key: value ํ˜•ํƒœ๋กœ ์ €์žฅํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ํƒํ•˜์—ฌ key: ์ฑ„ํŒ…๋ฐฉ ์•„์ด๋””๋กœ value: scheduler_instance๋กœ ์ €์žฅํ•˜์—ฌ ํ›„์— ์š”์ฒญ์ด ์™”์„ ๊ฒฝ์šฐ ๋น ๋ฅด๊ฒŒ ๋งค์นญ์„ ํ†ตํ•ด ๋ณธ๋ž˜์˜ ์Šค์ผ€์ค„๋Ÿฌ๋ฅผ ์ฐพ์•„ ๊ฐˆ ์ˆ˜ ์žˆ๋„๋ก ํ•˜์—ฌ ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜์˜€๋‹ค.

์ฐธ๊ณ  ํŽ˜์ด์ง€

APScheduler docs
An elegant way to run periodic tasks in python
RLock
Python with statement

0๊ฐœ์˜ ๋Œ“๊ธ€