diff --git a/README.md b/README.md index d72c493..41d6db8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # ๐Ÿฆ Team Backend ๐Ÿฆ ๐Ÿ™‹ ๋ชจ์—ฌํ†ค ๋ฐฑ์—”๋“œ ๋ ˆํฌ์ง€ํ† ๋ฆฌ +โš ๏ธ ํ‘ธ์‰ฌํ–ˆ๋‹ค๋ฉด ๊ผญ ๋งํ•ด์ฃผ๊ธฐ + ## ๐Ÿง‘โ€๐Ÿ’ป ๋ฉค๋ฒ„ |์ด๋ฆ„|[์ด์˜ˆ์€](https://github.com/eunxeum)|[์†ก์„ฑ๋ฏผ](https://github.com/tjdals4716)|[๋ฐ•์ œ์˜](https://github.com/Zero982)| |:---:|:---:|:---:|:---:| @@ -21,7 +23,7 @@ ### ๐Ÿš€ Deployment

- +

### ๐Ÿ—ฃ๏ธ Communication @@ -32,7 +34,4 @@ ## ์„œ๋ฒ„ ํ”Œ๋กœ์šฐ ๋™์ž‘

์นด์นด์˜ค ๋กœ๊ทธ์ธ -

- -## API ๋™์ž‘ -- ์ถ”๊ฐ€ ์˜ˆ์ • \ No newline at end of file +

\ No newline at end of file diff --git a/appspec.yml b/appspec.yml new file mode 100644 index 0000000..068b167 --- /dev/null +++ b/appspec.yml @@ -0,0 +1,26 @@ +version: 0.0 #CodeDeploy ๋ฒ„์ „์„(๋ฌด์กฐ๊ฑด 0.0์œผ๋กœ ๊ณ ์ •) +os: linux +files: + - source: / #destination์œผ๋กœ ์ด๋™์‹œํ‚ฌ ํŒŒ์ผ. ์—ฌ๊ธฐ์„œ๋Š” ์ „์ฒด ํŒŒ์ผ์„ ์˜๋ฏธ. + destination: /home/ec2-user/app/zip/ #source์—์„œ ์ง€์ •๋œ ํŒŒ์ผ์„ ๋ฐ›๋Š” ์œ„์น˜ + overwrite: yes #๊ธฐ์กด ํŒŒ์ผ๋“ค์„ ๋ฎ์–ด์“ธ์ง€ ์—ฌ๋ถ€ + +permissions: #CodeDeploy์—์„œ EC2 ์„œ๋ฒ„๋กœ ๋„˜๊ฒจ์ค€ ํŒŒ์ผ๋“ค์„ ๋ชจ๋‘ ec2-user ๊ถŒํ•œ์„ ๊ฐ–๋„๋ก ํ•จ + - object: / + pattern: "**" + owner: ec2-user + group: ec2-user + +hooks: + AfterInstall: + - location: stop.sh #์—”์ง„์—‘์Šค์™€ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์€ ์Šคํ”„๋ง ๋ถ€ํŠธ๋ฅผ ์ข…๋ฃŒ + timeout: 60 + runas: ec2-user #stop.sh๋ฅผ ec2-user ๊ถŒํ•œ์œผ๋กœ ์‹คํ–‰ + ApplicationStart: + - location: start.sh #์—”์ง„์—‘์Šค์™€ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ์ง€ ์•Š์€ Port๋กœ ์ƒˆ ๋ฒ„์ „์˜ ์Šคํ”„๋ง ๋ถ€ํŠธ๋ฅผ ์‹œ์ž‘ + timeout: 60 + runas: ec2-user + ValidateService: + - location: health.sh #์ƒˆ ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์‹คํ–‰๋๋Š”์ง€ ํ™•์ธ + timeout: 60 + runas: ec2-user \ No newline at end of file diff --git a/build.gradle b/build.gradle index 5358dcc..8c73de6 100644 --- a/build.gradle +++ b/build.gradle @@ -56,3 +56,7 @@ dependencies { tasks.named('test') { useJUnitPlatform() } + +jar{ + enabled = false +} \ No newline at end of file diff --git a/scripts/health.sh b/scripts/health.sh new file mode 100644 index 0000000..e0c9830 --- /dev/null +++ b/scripts/health.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash + +ABSPATH=$(readlink -f $0) +ABSDIR=$(dirname $ABSPATH) +source ${ABSDIR}/profile.sh +source ${ABSDIR}/switch.sh + +IDLE_PORT=$(find_idle_port) + +echo "> Health Check Start!" +echo "> IDLE_PORT: $IDLE_PORT" +echo "> curl -s http://127.0.0.1:$IDLE_PORT/profile" +sleep 10 + +for RETRY_COUNT in {1..10} +do + RESPONSE=$(curl -s http://127.0.0.1:${IDLE_PORT}/profile) + UP_COUNT=$(echo ${RESPONSE} | grep 'real' | wc -l) + + if [ ${UP_COUNT} -ge 1 ] # Nginx์™€ ์—ฐ๊ฒฐ๋˜์ง€ ์•Š์€ ํฌํŠธ๋กœ ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ž˜ ์‹คํ–‰๋˜์—ˆ๋Š”์ง€ ์ฒดํฌ + then # $up_count >= 1 ("real" ๋ฌธ์ž์—ด์ด ์žˆ๋Š”์ง€ ๊ฒ€์ฆ) + echo "> Health Check ์„ฑ๊ณต" + switch_proxy # ์ž˜ ์‹คํ–‰๋˜์–ด ์žˆ๋‹ค๋ฉด ํ”„๋ก์‹œ ์„ค์ •์„ ๋ณ€๊ฒฝ + break + else + echo "> Health Check์˜ ์‘๋‹ต์„ ์•Œ ์ˆ˜ ์—†๊ฑฐ๋‚˜ ํ˜น์€ ์‹คํ–‰ ์ƒํƒœ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค." + echo "> Health Check: ${RESPONSE}" + fi + + if [ ${RETRY_COUNT} -eq 10 ] + then + echo "> Health check ์‹คํŒจ. " + echo "> ์—”์ง„์—‘์Šค์— ์—ฐ๊ฒฐํ•˜์ง€ ์•Š๊ณ  ๋ฐฐํฌ๋ฅผ ์ข…๋ฃŒํ•ฉ๋‹ˆ๋‹ค." + exit 1 + fi + + echo "> Health check ์—ฐ๊ฒฐ ์‹คํŒจ. ์žฌ์‹œ๋„..." + sleep 10 +done \ No newline at end of file diff --git a/scripts/profile.sh b/scripts/profile.sh new file mode 100644 index 0000000..462762b --- /dev/null +++ b/scripts/profile.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +# ์‰ฌ๊ณ  ์žˆ๋Š” profile ์ฐพ๊ธฐ +# real1์ด ์‚ฌ์šฉ ์ค‘์ด๋ฉด real2๊ฐ€ ์‰ฌ๊ณ  ์žˆ๊ณ  ๋ฐ˜๋Œ€๋ฉด real1์ด ์‰ฌ๊ณ  ์žˆ์Œ + +function find_idle_profile() { + RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" https://newteamsgoody.shop/profile) # ํ˜„์žฌ Nginx๊ฐ€ ๋ฐ”๋ผ๋ณด๊ณ  ์žˆ๋Š” ์Šคํ”„๋ง ๋ถ€ํŠธ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰ ์ค‘์ธ์ง€ ํ™•์ธํ•˜๊ณ  ์‘๋‹ต๊ฐ’์œผ๋กœ ์ƒํƒœ์ฝ”๋“œ๋ฅผ ์ „๋‹ฌ๋ฐ›์Œ + + if [ ${RESPONSE_CODE} -ge 400 ] # 400๋ฒˆ๋Œ€ ์ด์ƒ์˜ ์˜ค๋ฅ˜์ผ ๊ฒฝ์šฐ real2๋ฅผ ์‚ฌ์šฉ + then + CURRENT_PROFILE=real2 + else + CURRENT_PROFILE=$(curl -s https://newteamsgoody.shop/profile) + fi + + if [ ${CURRENT_PROFILE} == real1 ] + then + IDLE_PROFILE=real2 + else + IDLE_PROFILE=real1 + fi + + echo "${IDLE_PROFILE}" # bash ์Šคํฌ๋ฆฝํŠธ๋Š” ๋ฐ˜ํ™˜ ๊ธฐ๋Šฅ์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— echo๋กœ ๊ฐ’์„ ์ถœ๋ ฅํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์—์„œ ๊ทธ ๊ฐ’์„ ์žก์•„์„œ ์‚ฌ์šฉ +} + +# ์‰ฌ๊ณ  ์žˆ๋Š” profile์˜ port ์ฐพ๊ธฐ +function find_idle_port() { + IDLE_PROFILE=$(find_idle_profile) + + if [ ${IDLE_PROFILE} == real1 ] + then + echo "8081" + else + echo "8082" + fi +} \ No newline at end of file diff --git a/scripts/start.sh b/scripts/start.sh new file mode 100644 index 0000000..0ff9da2 --- /dev/null +++ b/scripts/start.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash + +ABSPATH=$(readlink -f $0) +ABSDIR=$(dirname $ABSPATH) +source ${ABSDIR}/profile.sh + +REPOSITORY=/home/ec2-user/app + +echo "> Build ํŒŒ์ผ์„ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค." + +cp $REPOSITORY/zip/*.jar $REPOSITORY/ + +echo "> ์ƒˆ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฐฐํฌ" +JAR_NAME=$(ls -tr $REPOSITORY/*.jar | tail -n 1) + +echo "> JAR NAME: $JAR_NAME" + +echo "> $JAR_NAME ์— ์‹คํ–‰ ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•ฉ๋‹ˆ๋‹ค." + +chmod +x $JAR_NAME + +IDLE_PROFILE=$(find_idle_profile) + +echo "> ์ƒˆ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ $IDLE_PROFILE ๋กœ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค." + +# ์„ค์ • ํŒŒ์ผ์˜ ์œ„์น˜๋ฅผ ์ง€์ •ํ•˜๊ณ  active profile์„ ํ†ตํ•ด ๊ตฌ๋™๋  ํฌํŠธ๋ฅผ ์ง€์ • +nohup java -jar \ +-Dspring.config.location=$REPOSITORY/config/application.yml,\ +$REPOSITORY/config/application-prod.yml,\ +$REPOSITORY/config/application-$IDLE_PROFILE.yml \ +-Dspring.profiles.active=$IDLE_PROFILE,prod \ +$JAR_NAME > $REPOSITORY/nohup.out 2>&1 & \ No newline at end of file diff --git a/scripts/stop.sh b/scripts/stop.sh new file mode 100644 index 0000000..c082b70 --- /dev/null +++ b/scripts/stop.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +ABSPATH=$(readlink -f $0) # ํ˜„์žฌ stop.sh๊ฐ€ ์†ํ•ด ์žˆ๋Š” ๊ฒฝ๋กœ๋ฅผ ์ฐพ์Œ + +ABSDIR=$(dirname $ABSPATH) +source ${ABSDIR}/profile.sh # ์ผ์ข…์˜ import ๊ตฌ๋ฌธ์œผ๋กœ stop.sh์—์„œ๋„ profile.sh์˜ function์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•จ + +IDLE_PORT=$(find_idle_port) + +echo "> $IDLE_PORT ์—์„œ ๊ตฌ๋™ ์ค‘์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ pid ํ™•์ธ" +IDLE_PID=$(lsof -ti tcp:${IDLE_PORT}) + +if [ -z ${IDLE_PID} ] +then + echo "> ํ˜„์žฌ ๊ตฌ๋™ ์ค‘์ธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์—†์œผ๋ฏ€๋กœ ์ข…๋ฃŒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค." +else + echo "> kill -9 $IDLE_PID" + kill -9 ${IDLE_PID} + sleep 5 +fi \ No newline at end of file diff --git a/scripts/switch.sh b/scripts/switch.sh new file mode 100644 index 0000000..6eb49bc --- /dev/null +++ b/scripts/switch.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +ABSPATH=$(readlink -f $0) +ABSDIR=$(dirname $ABSPATH) +source $ABSDIR/profile.sh + +function switch_proxy() { + IDLE_PORT=$(find_idle_port) + + echo "> ์ „ํ™˜ํ•  port: $IDLE_PORT" + echo "> Port ์ „ํ™˜" + echo "set \$service_url http://127.0.0.1:${IDLE_PORT};" | sudo tee /etc/nginx/conf.d/service-url.inc # ์—”์ง„์—‘์Šค๊ฐ€ ๋ณ€๊ฒฝํ•  ํ”„๋ก์‹œ ์ฃผ์†Œ๋ฅผ ์ƒ์„ฑํ•˜์—ฌ service-url.inc๋กœ ๋ฎ์–ด ์”€ + + echo "> ์—”์ง„์—‘์Šค Reload" + sudo systemctl reload nginx +} \ No newline at end of file diff --git a/src/main/java/com/example/moyeothon/Config/Swagger/SwaggerConfig.java b/src/main/java/com/example/moyeothon/Config/Swagger/SwaggerConfig.java index 89a6aa0..54d1fbc 100644 --- a/src/main/java/com/example/moyeothon/Config/Swagger/SwaggerConfig.java +++ b/src/main/java/com/example/moyeothon/Config/Swagger/SwaggerConfig.java @@ -6,6 +6,7 @@ import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; import io.swagger.v3.oas.models.servers.Server; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -14,6 +15,9 @@ @Configuration public class SwaggerConfig { + @Value("${swagger.server-url}") + private String serverUrl; + @Bean public OpenAPI openAPI() { String securitySchemeName = "๋กœ๊ทธ์ธ ํ›„ ๋ฐœ๊ธ‰๋ฐ›์€ JWT ์ ์šฉํ•˜๊ธฐ"; @@ -28,13 +32,13 @@ public OpenAPI openAPI() { )) .addSecurityItem(new SecurityRequirement().addList(securitySchemeName)) .info(apiInfo()) - .servers(List.of(new Server().url("https://newteamsgoody.com"))); // HTTPS ์„œ๋ฒ„ ์„ค์ • + .servers(List.of(new Server().url(serverUrl))); } private Info apiInfo() { return new Info() .title("\uD83E\uDD81 ๋ฉ‹์‚ฌ ๋ชจ์—ฌํ†ค 10ํŒ€ ์Šค์›จ๊ฑฐ \uD83D\uDC8E") - .description("๋ชจ์—ฌํ†ค 10ํŒ€์˜ ์Šค์›จ๊ฑฐ์ž…๋‹ˆ๋‹ค.") + .description("๋ชจ์—ฌํ†ค 10ํŒ€์˜ ์Šค์›จ๊ฑฐ์ž…๋‹ˆ๋‹ค") .version("1.0.0"); } } diff --git a/src/main/java/com/example/moyeothon/Controller/MessageController.java b/src/main/java/com/example/moyeothon/Controller/MessageController.java index a971013..a84426d 100644 --- a/src/main/java/com/example/moyeothon/Controller/MessageController.java +++ b/src/main/java/com/example/moyeothon/Controller/MessageController.java @@ -46,8 +46,8 @@ public ResponseEntity deleteMessage(@PathVariable Long messageId, @P return ResponseEntity.ok(messageService.deleteMessage(messageId, uid, userDetails)); } - // ํ•ด๋‹น ์œ ์ € ์ชฝ์ง€ ์ „์ฒด ์กฐํšŒ - @Operation(summary = "ํ•ด๋‹น ์œ ์ € ์ชฝ์ง€ ์ „์ฒด ์กฐํšŒ") + // ํ•ด๋‹น ์œ ์ € ์†ก์ˆ˜์‹  ์ชฝ์ง€ ์ „์ฒด ์กฐํšŒ + @Operation(summary = "ํ•ด๋‹น ์œ ์ € ์†ก์ˆ˜์‹  ์ชฝ์ง€ ์ „์ฒด ์กฐํšŒ") @GetMapping("/user/{uid}") public ResponseEntity> getAllMessagesForUser(@PathVariable String uid, @AuthenticationPrincipal UserDetails userDetails) { return ResponseEntity.ok(messageService.getAllMessagesForUser(uid, userDetails)); diff --git a/src/main/java/com/example/moyeothon/Repository/MessageRepository.java b/src/main/java/com/example/moyeothon/Repository/MessageRepository.java index 8760eca..972f72f 100644 --- a/src/main/java/com/example/moyeothon/Repository/MessageRepository.java +++ b/src/main/java/com/example/moyeothon/Repository/MessageRepository.java @@ -6,7 +6,7 @@ import java.util.List; public interface MessageRepository extends JpaRepository { - List findAllBySenderUidAndReceiverUid(String senderId, String receiverId); + List findAllBySenderUidOrReceiverUid(String senderId, String receiverId); List findBySenderUid(String senderId); List findByReceiverUid(String receiverId); List findByContentContainingIgnoreCase(String keyword); diff --git a/src/main/java/com/example/moyeothon/Service/MessageService.java b/src/main/java/com/example/moyeothon/Service/MessageService.java index 0daab93..0321e12 100644 --- a/src/main/java/com/example/moyeothon/Service/MessageService.java +++ b/src/main/java/com/example/moyeothon/Service/MessageService.java @@ -77,12 +77,12 @@ public MessageDTO deleteMessage(Long messageId, String uid, UserDetails userDeta return MessageDTO.entityToDTO(messageEntity); } - // ํ•ด๋‹น ์œ ์ € ์ชฝ์ง€ ์ „์ฒด ์กฐํšŒ + // ํ•ด๋‹น ์œ ์ € ์†ก์ˆ˜์‹  ์ชฝ์ง€ ์ „์ฒด ์กฐํšŒ public List getAllMessagesForUser(String uid, UserDetails userDetails) { if (!userDetails.getUsername().equals(uid)) { throw new RuntimeException("์ธ์ฆ๋˜์ง€ ์•Š์€ ์œ ์ €์ž…๋‹ˆ๋‹ค."); } - return messageRepository.findAllBySenderUidAndReceiverUid(uid, uid) + return messageRepository.findAllBySenderUidOrReceiverUid(uid, uid) .stream() .map(MessageDTO::entityToDTO) .collect(Collectors.toList()); diff --git a/src/main/resources/application-real1.yml b/src/main/resources/application-real1.yml new file mode 100644 index 0000000..54b155f --- /dev/null +++ b/src/main/resources/application-real1.yml @@ -0,0 +1,2 @@ +server: + port: 8081 \ No newline at end of file diff --git a/src/main/resources/application-real2.yml b/src/main/resources/application-real2.yml new file mode 100644 index 0000000..0884131 --- /dev/null +++ b/src/main/resources/application-real2.yml @@ -0,0 +1,2 @@ +server: + port: 8082 \ No newline at end of file