kookmin-sw / capstone-2023-05

capstone-2023-05 created by GitHub Classroom
https://capstone-2023-05.vercel.app
0 stars 0 forks source link

feat: select ads #64

Closed Jaewook-Lee closed 1 year ago

Jaewook-Lee commented 1 year ago

이 PR은 #54 이슈를 구현했습니다.

WebSocket을 통해 새로운 Ads를 랜덤하게 얻는 기능을 수행할 수 있습니다.

테스트 전

본 기능은 다음의 과정까지 수행한 후 테스트를 해야 합니다.
더 확실한 실행 결과를 확인하기 위해 최소 3개의 connection을 사용하는 것을 추천합니다.

또한 Opinion 테이블에 충분한 양의 의견들이 있어야 합니다. 로컬 테스트에서 사용했던 테이블 내용은 아래의 csv 파일로 공유합니다.
Opinion_Table.csv

테스트 방법

  1. 토론 Host의 connection에서 preparationStart 액션을 요청합니다.
    스크린샷 2023-05-05 17-09-36
  2. refresh 주기에 맞춰 websocket 메세지가 전송되는지 확인합니다. 호스트와 참여자가 받는 메세지의 내용이 다릅니다. 따라서 다음의 사항을 체크하셔야 합니다.
    • 호스트는 양 팀의 Ads를 모두 받았는가?
    • Team ID '1'에 속한 connection들은 1팀의 의견들만을 새로운 Ads로 받았는가?
    • Team ID '2'에 속한 connection들은 2팀의 의견들만을 새로운 Ads로 받았는가?

테스트가 성공적이라면 아래와 같은 메세지들을 받아야 합니다.

에러 없이 N번의 refresh 동안 메세지들을 받았다면 테스트는 성공입니다.

seungholee-dev commented 1 year ago

상세한 가이드와 설명 감사합니다. 이해가 쉽네요!

제가 Host에서 InitJoin 후에 preparationStart를 하는 과정에서 아래와 같은 에러가 뜨네요 ㅠ

Traceback (most recent call last):
  File "/home/seungho/Desktop/CS/capstone-2023-05/backend/node_modules/serverless-offline/src/lambda/handler-runner/python-runner/invoke.py", line 97, in <module>

    result = handler(input['event'], context)
  File "/home/seungho/Desktop/CS/capstone-2023-05/backend/src/utility/websocket.py", line 37, in wrapper
    return func(event, context, wsclient)
  File "/home/seungho/Desktop/CS/capstone-2023-05/backend/src/lambda/handler.py", line 75, in preparation_start_handler
    return app.preparation_start_handler(event, context, wsclient)
  File "/home/seungho/Desktop/CS/capstone-2023-05/backend/src/game/app.py", line 285, in preparation_start_handler

tmp[idx].extend(random.sample(candidates[idx], sampling_number))
  File "/usr/lib/python3.8/random.py", line 363, in sample
    raise ValueError("Sample larger than population or is negative")
ValueError: Sample larger than population or is negative

주요 원인이 ValueError: Sample larger than population or is negative인데, 검색해보니 Sampling의 개수를 잔존 개수보다 많게 할 경우 생긴다고 하네요! 원인이 뭔지 파악 중이요!

Jaewook-Lee commented 1 year ago

혹시 토론 참가자들의 vote 과정보다 먼저 host 접속 -> preparationStart 를 요청했나요?
만약 참가자들의 vote 전에 호스트가 preparationStart 요청을 한다면 candidates 변수에 담기는 값이 없어서 에러가 생길 수도 있습니다.
로컬 테스트 진행 상황을 더 상세히 공유할 수 있다면 더 빠른 원인 파악이 가능할 것 같아요.

seungholee-dev commented 1 year ago

음 원인을 찾은 것 같기두 한데요, 혹시 저희 dynamodb-creat-table.sh 업데이터 되었나요? vote과정에서는 teamID와 여러 정보가 Dynamodb에 저장되는 것을 확인했으나 create-table.sh에는 해당 정보가 없더라구요 ㅠ

Jaewook-Lee commented 1 year ago

혹시 저희 dynamodb-creat-table.sh 업데이터 되었나요?

dynamodb-create-table.sh 파일은 #59 PR에서 변경된대로 사용하고 있습니다.
DynamoDB에 저장됐지만 dynamodb-create-table.sh에 내용이 없다는 말이 이해가 잘 안되는데 혹시 그와 관련해서 이미지를 올리거나 더 상세한 설명을 할 수 있을까요?

seungholee-dev commented 1 year ago

해당 부분 로컬에서 테이블에는 문제가 없는 것 같네요 local GUI로 확인중이에요! 잠시만요

seungholee-dev commented 1 year ago

감사합니다! 덕분에 테스팅 성공했어요 :) Host와 User 둘 다 성공적으로 일정 시간마다 랜덤으로 가져오네요

{
    "action": "recvNewAds",
    "result": "success",
    "newAds": [
        {
            "userId": "ho@kookmin.ac.kr",
            "likes": 0,
            "content": "Opinion 39"
        },
        {
            "userId": "ho@kookmin.ac.kr",
            "likes": 0,
            "content": "Opinion 44"
        },
        {
            "userId": "ho@kookmin.ac.kr",
            "likes": 0,
            "content": "Opinion 74"
        },
        {
            "userId": "wuk@kookmin.ac.kr",
            "likes": 0,
            "content": "Opinion 65"
        },
        {
            "userId": "wuk@kookmin.ac.kr",
            "likes": 0,
            "content": "Opinion 5"
        },
        {
            "userId": "ho@kookmin.ac.kr",
            "likes": 0,
            "content": "Opinion 29"
        },
        {
            "userId": "wuk@kookmin.ac.kr",
            "likes": 0,
            "content": "Opinion 40"
        },
        {
            "userId": "wuk@kookmin.ac.kr",
            "likes": 0,
            "content": "Opinion 70"
        },
        {
            "userId": "wuk@kookmin.ac.kr",
            "likes": 0,
            "content": "Opinion 45"
        },
        {
            "userId": "ho@kookmin.ac.kr",
            "likes": 0,
            "content": "Opinion 24"
        },
        {
            "userId": "joon@kookmin.ac.kr",
            "likes": 0,
            "content": "Opinion 21"
        },
        {
            "userId": "joon@kookmin.ac.kr",
            "likes": 0,
            "content": "Opinion 66"
        }
    ]
}

에러가 났던 이유 중에 중간에 다른 함수가 작동하지 않았던 것을 알았는데 혹시 아래 정보로 initJoin 되는지 확인 부탁드려도 되나요?! DB 정보랑 일치하지만 initJoin 응답이 안생기더라구요.

{
  "action": "initJoin",
  "battleId": "ABC123",
  "userId": hoon@kookmin.ac.kr",
  "nickname": "sch"
}
seungholee-dev commented 1 year ago

앗 무시해주세요 따옴표를 빼먹었네요! hoon@kookmin.ac.kr에서 앞쪽 따옴표를 빼먹었어요 ㅠ 어쩐지 이것만 에러나는게 이상했는데

성공적으로 동작확인이요!!!!

Binsk-dev commented 1 year ago

혹시 CSV 파일을 DB에 반영하는 하실 때 다들 어떻게 하셨나요???

Jaewook-Lee commented 1 year ago

혹시 CSV 파일을 DB에 반영하는 하실 때 다들 어떻게 하셨나요???

저는 DBeaver 프로그램을 사용하고 있는데, 프로그램에서 '데이터 가져오기' 기능을 사용해서 CSV 파일을 DB에 반영했어요.
아마 프로그램 별로 이런 기능이 있지 않을까 싶네요!

Binsk-dev commented 1 year ago

vote api에서 뭔가 막히는데 혹시 제가 모르는 동안 스펙 변경이 있었나요???

> {"action": "vote", "round": 1, "teamId": 1}
< {"connectionId":"427f6f3a-551d-47e7-b798-5f4e512aa581","message":"Internal server error","requestId":"1234567890"}
seungholee-dev commented 1 year ago

음 제가 개발 중에 다시 확인해봤는데요 다시 에러가 발생하네요 ㅠ

  1. Host initJoin
  2. 각팀 한 명씩 initJoin
  3. User vote 시행
  4. Host preparationStart 시행

하면 아까와 같은 에러가 나오네요 ㅠ

  tmp[idx].extend(random.sample(candidates[idx], sampling_number))
  File "/usr/lib/python3.8/random.py", line 363, in sample

    raise ValueError("Sample larger than population or is negative")
ValueError: Sample larger than population or is negative

sampling의 수를 낮추면 에러가 나지 않아서 확인해보니 어쩌면 이 쿼리문 때문인 것 같더라구요. 위의 에러문은 뽑는 개수가 잔존 개수보다 많을 때 나타나는 에러라구해서 조사를 해본 결과,

select_query = f"""SELECT ("Opinion"."userId","Opinion"."battleId","Opinion"."roundNo","Opinion"."order","Opinion"."noOfLikes","Opinion"."content","Opinion"."status","Support"."vote") FROM "Opinion", "Support" 
        WHERE "Opinion"."userId" = "Support"."userId" and "Opinion"."battleId" = '{my_battle_id}' and "Support"."battleId" = '{my_battle_id}' and "Opinion"."roundNo" = {curr_round} and "Support"."roundNo" = {curr_round} and status != 'REPORTED'"""
        rows = psql_ctx.execute_query(select_query)

여기서 저희가 라운드의 모든 의견을 가져오는 과정에서 Opinion.userId = Support.userId라는 조건을 사용하는데 이 부분에서 자기가 냈던 의견만 가져오는 것 같더라구요 ㅜㅠ 그래서 의견 개수가 많아도 본인이 낸 의견의 개수가 적으면 에러가 나는가 싶어요! 예시로 제공해주신 csv파일에서 실제로 한 유저가 한 라운드에서 각자 낸 의견의 개수가 12개를 넘지 못해서 나는 에러 같아요!

teamID가 컬럼 값으로 없어서 해당 코드가 포함된 것 같은데 저희 조인 사용해보는 거 어떤가요?!

Jaewook-Lee commented 1 year ago

vote api에서 뭔가 막히는데 혹시 제가 모르는 동안 스펙 변경이 있었나요???

작성하신 request에서 teamID 값을 string으로 바꾸고 다시 시도해보시겠어요? 제가 제대로 전달을 못 한 것 같네요 ㅜㅜ

seungholee-dev commented 1 year ago

@Binsk-dev 저희 Vote하면서 기존에 RDS Support Table에 이미 Vote한 내역있으면 충돌일어나더라구요 그래서 테스트 시에는 삭제해주고 다시 해주셔야해요!

Jaewook-Lee commented 1 year ago

여기서 저희가 라운드의 모든 의견을 가져오는 과정에서 Opinion.userId = Support.userId라는 조건을 사용하는데 이 부분에서 자기가 냈던 의견만 가져오는 것 같더라구요 ㅜㅠ 그래서 의견 개수가 많아도 본인이 낸 의견의 개수가 적으면 에러가 나는가 싶어요! 예시로 제공해주신 csv파일에서 실제로 한 유저가 한 라운드에서 각자 낸 의견의 개수가 12개를 넘지 못해서 나는 에러 같아요! teamID가 컬럼 값으로 없어서 해당 코드가 포함된 것 같은데 저희 조인 사용해보는 거 어떤가요?!

  1. Opinion.userId = Support.userId 조건은 자기가 냈던 의견만 가져오는 것이 아닌, Support 테이블과 Opinion 테이블에 같이 존재하는 userId를 대상으로 한다는 표현이 조금 더 정확할 것 같아요(사실 이 설명도 승호 형의 설명과 차이가 크게 안 느껴지지만..) 자신의 의견만 가져온다고 느끼는 이유는 각 팀의 참여자가 1명만 있기 때문이에요.
  2. Opinion_Table.csv 파일에서 한 라운드에서 각자가 낸 총 의견의 수는 16개로 통일 시켰습니다. 따라서 각자 낸 의견의 수가 12개를 넘지 못해서 나는 에러는 아닐 것 같아요. 일단 승호 형이 진행한대로 저도 로컬 테스트 다시 하면서 원인 찾아보도록 할게요.
  3. 저 SQL문을 작성할 때 JOIN을 목적으로 작성한 것인데 제가 아직 SQL 문법이 익숙하지 않았나봐요 ^^; 좀 더 JOIN 의도가 명확히 드러나도록 다시 작성할게요~
Binsk-dev commented 1 year ago

뭔가 동작은 되는 것 같은데 찜찜하네요. 아래는 제가 웹소켓 CLI 툴을 이용해서 테스트한 결과인데 밑에서 preparationStart 를 실행했는데 응답으로 인터널 서버 에러가 등장했다가 갑자기 추가로 기대했던 응답을 주는 걸 보면 음... 뭐가 문제일까요? 일단 해당 테스트는 지금 학교에서 집에 있는 원격서버로 확인한거긴 합니다만 혹시 짐작가는 에러가 있을까요???

❯ wscat --connect ws://localhost:3001
Connected (press CTRL+C to quit)
> {"action": "initJoin", "battleId": "ABC123", "userId": "joon@kookmin.ac.kr", "nickname": "lyj"}
< {"action": "initJoinResult", "result": "success", "teams": [{"teamId": 1, "teamName": "Team Door"}, {"teamId": 2, "teamName": "Team Wheel"}]}
> {"action": "preparationStart", "round": 1, "battleId": "ABC123"}
< {"connectionId":"1bb57002-1cfb-461a-92c5-3550557d3719","message":"Internal server error","requestId":"1234567890"}
> {"action": "preparationStart", "round": 1, "battleId": "ABC123"}
< {"connectionId":"1bb57002-1cfb-461a-92c5-3550557d3719","message":"Internal server error","requestId":"1234567890"}
< {"action": "recvNewAds", "result": "success", "newAds": [[{"userId": "wuk@kookmin.ac.kr", "likes": 0, "content": "Opinion 45"}, {"userId": "wuk@kookmin.ac.kr", "likes": 0, "content": "Opinion 55"}, {"userId": "wuk@kookmin.ac.kr", "likes": 0, "content": "Opinion 5"}, {"userId": "wuk@kookmin.ac.kr", "likes": 0, "content": "Opinion 20"}, {"userId": "wuk@kookmin.ac.kr", "likes": 0, "content": "Opinion 35"}, {"userId": "wuk@kookmin.ac.kr", "likes": 0, "content": "Opinion 0"}, {"userId": "wuk@kookmin.ac.kr", "likes": 0, "content": "Opinion 60"}, {"userId": "wuk@kookmin.ac.kr", "likes": 0, "content": "Opinion 40"}, {"userId": "wuk@kookmin.ac.kr", "likes": 0, "content": "Opinion 70"}, {"userId": "wuk@kookmin.ac.kr", "likes": 0, "content": "Opinion 65"}, {"userId": "wuk@kookmin.ac.kr", "likes": 0, "content": "Opinion 25"}, {"userId": "wuk@kookmin.ac.kr", "likes": 0, "content": "Opinion 15"}], [{"userId": "ho@kookmin.ac.kr", "likes": 0, "content": "Opinion 79"}, {"userId": "ho@kookmin.ac.kr", "likes": 0, "content": "Opinion 34"}, {"userId": "ho@kookmin.ac.kr", "likes": 0, "content": "Opinion 29"}, {"userId": "ho@kookmin.ac.kr", "likes": 0, "content": "Opinion 54"}, {"userId": "ho@kookmin.ac.kr", "likes": 0, "content": "Opinion 14"}, {"userId": "ho@kookmin.ac.kr", "likes": 0, "content": "Opinion 24"}, {"userId": "ho@kookmin.ac.kr", "likes": 0, "content": "Opinion 4"}, {"userId": "ho@kookmin.ac.kr", "likes": 0, "content": "Opinion 44"}, {"userId": "ho@kookmin.ac.kr", "likes": 0, "content": "Opinion 74"}, {"userId": "ho@kookmin.ac.kr", "likes": 0, "content": "Opinion 64"}, {"userId": "ho@kookmin.ac.kr", "likes": 0, "content": "Opinion 69"}, {"userId": "ho@kookmin.ac.kr", "likes": 0, "content": "Opinion 39"}]]}
>
Binsk-dev commented 1 year ago

@Binsk-dev 저희 Vote하면서 기존에 RDS Support Table에 이미 Vote한 내역있으면 충돌일어나더라구요 그래서 테스트 시에는 삭제해주고 다시 해주셔야해요!

위에서 vote 관련 문제는 중복 때문에 일어난게 아니더군요. 원래 DB에 support 인스턴스는 아무것도 없었던 상태였습니다.

seungholee-dev commented 1 year ago

여기서 저희가 라운드의 모든 의견을 가져오는 과정에서 Opinion.userId = Support.userId라는 조건을 사용하는데 이 부분에서 자기가 냈던 의견만 가져오는 것 같더라구요 ㅜㅠ 그래서 의견 개수가 많아도 본인이 낸 의견의 개수가 적으면 에러가 나는가 싶어요! 예시로 제공해주신 csv파일에서 실제로 한 유저가 한 라운드에서 각자 낸 의견의 개수가 12개를 넘지 못해서 나는 에러 같아요! teamID가 컬럼 값으로 없어서 해당 코드가 포함된 것 같은데 저희 조인 사용해보는 거 어떤가요?!

  1. Opinion.userId = Support.userId 조건은 자기가 냈던 의견만 가져오는 것이 아닌, Support 테이블과 Opinion 테이블에 같이 존재하는 userId를 대상으로 한다는 표현이 조금 더 정확할 것 같아요(사실 이 설명도 승호 형의 설명과 차이가 크게 안 느껴지지만..) 자신의 의견만 가져온다고 느끼는 이유는 각 팀의 참여자가 1명만 있기 때문이에요.
  2. Opinion_Table.csv 파일에서 한 라운드에서 각자가 낸 총 의견의 수는 16개로 통일 시켰습니다. 따라서 각자 낸 의견의 수가 12개를 넘지 못해서 나는 에러는 아닐 것 같아요. 일단 승호 형이 진행한대로 저도 로컬 테스트 다시 하면서 원인 찾아보도록 할게요.
  3. 저 SQL문을 작성할 때 JOIN을 목적으로 작성한 것인데 제가 아직 SQL 문법이 익숙하지 않았나봐요 ^^; 좀 더 JOIN 의도가 명확히 드러나도록 다시 작성할게요~

답변 감사드려요! Join이 Comma를 사용해서 되는 것 새로 배웠어요! Join 이대로 가져가도 되지 않을까 싶어요! https://stackoverflow.com/questions/20138355/whats-the-difference-between-comma-separated-joins-and-join-on-syntax-in-mysql

로컬에서 혹시 다른 문제가 있는지 확인해볼게요!

Binsk-dev commented 1 year ago

음... 뭔가 잘 되질 않네요. 승호님이 말씀하신 아래와 같은 에러도 발생하고 제 환경에서는 실행했을 때, 거의 LambdaTimeoutError[504]가 발생하네요. raise ValueError("Sample larger than population or is negative") ValueError: Sample larger than population or is negative

Jaewook-Lee commented 1 year ago

승호 형의 comment를 보고 생각해봤어요. "왜 처음에는 잘 됐지만, 다시 할 때는 에러가 났을까?"
여기에 집중해서 생각해보다 다음의 경우를 생각해봤어요. "만약 승호 형이 첫 번에 테스트를 끝내고 Opinion 테이블의 status들을 다시 CANDIDATE로 초기화 시켜주지 않고 다시 테스트를 진행했다면?"
여기에 포인트를 잡고 다시 코드를 보니 제 코드에서 다음의 문제점을 발견했습니다.

처음 요청할 때는 Ads에 있는 의견은 없으므로 무조건 12개의 새로운 CANDIDATE들을 반환해야 한다. > 
그런데 처음부터 12개 만큼의 충분한 CANDIDATE들이 없다면? > 
그래도 일단 무조건 12개 샘플링을 진행한다. > 
ValueError: Sample larger than population or is negative

제가 처음에는 무조건 12개 이상의 CANDIDATE는 존재할 것이라는 착각을 했던 것 같아요...
여러분들의 에러의 원인이 이 부분일지 모르겠지만 이에 대해 수정을 진행했고, DB의 의견들을 의도적으로 줄여서 다시 테스트 진행한 결과 성공했어요.
그러니 로컬 테스트를 다시 진행해서 결과가 어떤지 올려주세요!

Binsk-dev commented 1 year ago

일단 갯수에 대한 에러는 해결된 듯 보입니다. 그러나 저의 경우 여전히 LambdaTimeoutError[504]가 발생하네요. 다만 아래를 보시면 알겠지만 뭔가 뒷단에서 lambda 함수가 동작 중인 것 같긴 합니다.

테스트를 통해 다음과 같은 결과를 얻어냈습니다.

  1. preparationStart 을 수행할 때, 시간이 조금 지나고 인터널 서버 에러가 응답으로 옵니다.
  2. 그리고 조금 기다리면 성공한 것처럼 보이는 응답들이 추가로 옵니다.
  3. 이전에 제가 수행했을 때는 각 팀의 의견들이 담긴 리스트가 왔지만 이번 경우, 해당 팀의 의견들이 없고 호스트와 참가자 둘 다 빈 리스트가 응답으로 오더군요.
seungholee-dev commented 1 year ago

성공 확인했어요!! 와우!! 혹시 어떤 부분이 문제였나요?

Binsk-dev commented 1 year ago

@Jaewook-Lee 일단 제 문제는 제 개인환경에서 오는 듯하니 이건 제가 오늘 밤까지 해결해보고 안 되면 dev 브랜치로 머지해도 될 것 같습니다.

Jaewook-Lee commented 1 year ago

@PricelessCode 위에 제가 적은 가장 최신의 commet에서 언급한 부분이 문제였을 것이라 판단하고 있어요. 성공했다니 다행이에요.

Jaewook-Lee commented 1 year ago

이전에 제가 수행했을 때는 각 팀의 의견들이 담긴 리스트가 왔지만 이번 경우, 해당 팀의 의견들이 없고 호스트와 참가자 둘 다 빈 리스트가 응답으로 오더군요.

@Binsk-dev 한 번의 Internal Server Error 후 조금 있다 websocket 메세지가 오는 현상에 대한 원인은 아직 파악하지 못 했습니다.
저의 경우, 빈 리스트가 메세지에 담겨서 오는 경우는 CANDIDATE 상태인 의견이 없는 경우였습니다. 한 번의 로컬 테스트 이후, Opinion 테이블에서 status 값을 모두 CANDIDATE로 설정하는 과정 없이 바로 preparationStart 요청을 하면 이러한 상황이 생길 수 있어요. 혹시 DB에서 의견들의 status 값들 체크해 보셨나요?

Binsk-dev commented 1 year ago

오 상태가 문제였네요. 상태를 바꾸니 일단 빈리스트가 오진 않습니다. 다만 여전히 인터널 서버 에러가 발생하네요.. 이건 제가 따로 해결해보죠