Giter Site home page Giter Site logo

our-map-server's People

Contributors

9wan6zae avatar suhwanjee avatar zeniuus avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

our-map-server's Issues

liquibase 도입

  • 지금은 hibernate의 autoddl 기능을 사용하고 있는데(create-drop), 실제 서비스 운영을 하려면 이러면 당연히 안 되고 형상관리 툴을 사용해야 함.

IoC 컨테이너에 등록 편하게 하기

현재는 Angular처럼 각 서비스 / 레포지토리 등을 직접 KoinApplication에 넣어주고 있는데, Spring의 @ComponentScan 같은 게 있으면 좋겠다.

  • @DependencyInjected 같은 어노테이션 만들기
  • @DependencyInjected 달린 클래스를 스캔해서 module을 만들고 startKoin { }에 등록하기
    • 어노테이션 프로세서로 해야 하는가? 아니면 리플렉션이면 충분한가? -> Spring도 리플렉션을 사용하는 것 같으니 리플렉션으로 충분할 듯 하다.

CI/CD 최적화

아티팩트 저장 기능을 잘 활용하면 CI 과정에서 나온 빌드 결과물을 CD로 넘겨서 CD에서 한 번 더 빌드를 안 해도 되는 것으로 보인다.

서버 메트릭 수집

  • 1단계 - CPU & 메모리 사용량 & network I/O pressure 등의 기본적인 하드웨어 메트릭 수집
  • 2단계 - 어플리케이션 커스텀 메트릭 수집

트랜잭션 관리 고도화

#6 에서 대충 구현하긴 했는데, 아직 몇 가지 문제가 남아 있음.

  • isolation level 조절 안 됨
  • nested transaction을 연 경우 맨 안쪽의 트랜잭션이 종료되면 commit 되어버림

collate / charset 때문에 fk 추가 안 되는 문제 해결

첫 번째 liquibase script에서 charset = utf8mb4 / collate = utf8mb4_unicode_ci가 SQL 문에 박혀 있어서 몇 개 테이블이 utf8mb4로 이미 형성이 되어 있다. 이 때 1. 실제 DB 상의 our_map 데이터베이스의 기본 charset / collate가 이게 아니고, 2. jdbc URL에 charset / collate를 지정해도 이상하게 먹질 않아서 새로 생긴 테이블은 utf8mb4가 아니라 utf8(아마?)로 생기고, 이것 때문에 FK를 지정하면 liquibase 실행이 실패한다. 그래서 임시로 FK를 제거한 상황.

테라폼 리팩토링

테라폼이 모듈화가 안 되어 있어서 지난 번에 region 옮기는 작업을 했을 때 좀 고생했다. 모듈로 만들고, variable로 region / default vpc id / default subnet id를 받도록 변경하자.

서버를 안정적으로 배포할 수 있는 방법 찾기

  • 1단계 - 현재 docker run으로 서버를 띄우고 있는데, 한 번 프로세스가 죽으면 다시 자동으로 복구가 안 되는 개복치다. 서버를 띄운 채로 유지할 수 있는 방법을 찾아보자. (막 던지는 소리: systemd나 docker compose 같은 걸 찾아본다?)
  • 2단계 - 무중단 배포가 가능한 방법을 찾아보자. 왠지 docker compose로 가능할 것 같기도?

CD 다시 살리기

CD를 하면 아래 에러가 나면서 실행이 안 된다. 대충 읽어봤을 때는 ./gradlew installDist 할 때의 자바 버전이랑 해당 jar를 실행하는 도커 이미지 베이스의 자바 버전이 안 맞아서 그런 듯?

15:21:17.701 [eventLoopGroupProxy-4-1] ERROR exception.OurMapExceptionHandler - ourMap/protocol/SearchPlacesParams has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
java.lang.UnsupportedClassVersionError: ourMap/protocol/SearchPlacesParams has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
	at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
	at route.SearchPlacesKt$searchPlaces$1.invokeSuspend(SearchPlaces.kt:67)
	at route.SearchPlacesKt$searchPlaces$1.invoke(SearchPlaces.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
	at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:136)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:79)
	at io.ktor.routing.Routing.executeResult(Routing.kt:155)
	at io.ktor.routing.Routing.interceptor(Routing.kt:39)
	at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:107)
	at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
	at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
	at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:145)
	at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
	at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
	at io.ktor.features.StatusPages$interceptCall$2.invokeSuspend(StatusPages.kt:102)
	at io.ktor.features.StatusPages$interceptCall$2.invoke(StatusPages.kt)
	at io.ktor.features.StatusPages$interceptCall$2.invoke(StatusPages.kt)
	at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
	at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
	at io.ktor.features.StatusPages.interceptCall(StatusPages.kt:101)
	at io.ktor.features.StatusPages.access$interceptCall(StatusPages.kt:18)
	at io.ktor.features.StatusPages$Feature$install$2.invokeSuspend(StatusPages.kt:142)
	at io.ktor.features.StatusPages$Feature$install$2.invoke(StatusPages.kt)
	at io.ktor.features.StatusPages$Feature$install$2.invoke(StatusPages.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
	at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:136)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:79)
	at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invokeSuspend(DefaultEnginePipeline.kt:124)
	at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
	at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
	at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:136)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:79)
	at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invokeSuspend(NettyApplicationCallHandler.kt:123)
	at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
	at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
	at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:55)
	at kotlinx.coroutines.BuildersKt__Builders_commonKt.startCoroutineImpl(Builders.common.kt:194)
	at kotlinx.coroutines.BuildersKt.startCoroutineImpl(Unknown Source)
	at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:134)
	at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
	at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
	at io.ktor.server.netty.NettyApplicationCallHandler.handleRequest(NettyApplicationCallHandler.kt:43)
	at io.ktor.server.netty.NettyApplicationCallHandler.channelRead(NettyApplicationCallHandler.kt:34)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:61)
	at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:370)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.ktor.server.netty.EventLoopGroupProxy$Companion.create$lambda-1$lambda-0(NettyApplicationEngine.kt:251)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:748)
15:21:17.715 [eventLoopGroupProxy-4-1] ERROR Application - Unhandled: POST - /searchPlaces
java.lang.UnsupportedClassVersionError: ourMap/protocol/Model$OurMapError has been compiled by a more recent version of the Java Runtime (class file version 55.0), this version of the Java Runtime only recognizes class file versions up to 52.0
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
	at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
	at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
	at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
	at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
	at exception.OurMapExceptionHandler.handleUnexpectedError(OurMapExceptionHandler.kt:48)
	at exception.OurMapExceptionHandler.handle(OurMapExceptionHandler.kt:21)
	at OurMapServerKt$ourMapModule$3$1.invokeSuspend(OurMapServer.kt:70)
	at OurMapServerKt$ourMapModule$3$1.invoke(OurMapServer.kt)
	at io.ktor.features.StatusPages.interceptCall(StatusPages.kt:107)
	at io.ktor.features.StatusPages.access$interceptCall(StatusPages.kt:18)
	at io.ktor.features.StatusPages$interceptCall$1.invokeSuspend(StatusPages.kt)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.internal.ScopeCoroutine.afterResume(Scopes.kt:43)
	at kotlinx.coroutines.AbstractCoroutine.resumeWith(AbstractCoroutine.kt:106)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
	at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
	at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
	at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
	at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
	at io.ktor.util.pipeline.SuspendFunctionGun.access$resumeRootWith(SuspendFunctionGun.kt:15)
	at io.ktor.util.pipeline.SuspendFunctionGun$continuation$1.resumeWith(SuspendFunctionGun.kt:89)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:46)
	at io.ktor.util.pipeline.SuspendFunctionGun.resumeRootWith(SuspendFunctionGun.kt:194)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:165)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
	at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:136)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:79)
	at io.ktor.routing.Routing.executeResult(Routing.kt:155)
	at io.ktor.routing.Routing.interceptor(Routing.kt:39)
	at io.ktor.routing.Routing$Feature$install$1.invokeSuspend(Routing.kt:107)
	at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
	at io.ktor.routing.Routing$Feature$install$1.invoke(Routing.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
	at io.ktor.features.ContentNegotiation$Feature$install$1.invokeSuspend(ContentNegotiation.kt:145)
	at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
	at io.ktor.features.ContentNegotiation$Feature$install$1.invoke(ContentNegotiation.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
	at io.ktor.features.StatusPages$interceptCall$2.invokeSuspend(StatusPages.kt:102)
	at io.ktor.features.StatusPages$interceptCall$2.invoke(StatusPages.kt)
	at io.ktor.features.StatusPages$interceptCall$2.invoke(StatusPages.kt)
	at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:89)
	at kotlinx.coroutines.CoroutineScopeKt.coroutineScope(CoroutineScope.kt:264)
	at io.ktor.features.StatusPages.interceptCall(StatusPages.kt:101)
	at io.ktor.features.StatusPages.access$interceptCall(StatusPages.kt:18)
	at io.ktor.features.StatusPages$Feature$install$2.invokeSuspend(StatusPages.kt:142)
	at io.ktor.features.StatusPages$Feature$install$2.invoke(StatusPages.kt)
	at io.ktor.features.StatusPages$Feature$install$2.invoke(StatusPages.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
	at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:136)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:79)
	at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invokeSuspend(DefaultEnginePipeline.kt:124)
	at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
	at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$2.invoke(DefaultEnginePipeline.kt)
	at io.ktor.util.pipeline.SuspendFunctionGun.loop(SuspendFunctionGun.kt:248)
	at io.ktor.util.pipeline.SuspendFunctionGun.proceed(SuspendFunctionGun.kt:116)
	at io.ktor.util.pipeline.SuspendFunctionGun.execute(SuspendFunctionGun.kt:136)
	at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:79)
	at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invokeSuspend(NettyApplicationCallHandler.kt:123)
	at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
	at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
	at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:55)
	at kotlinx.coroutines.BuildersKt__Builders_commonKt.startCoroutineImpl(Builders.common.kt:194)
	at kotlinx.coroutines.BuildersKt.startCoroutineImpl(Unknown Source)
	at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:134)
	at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
	at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
	at io.ktor.server.netty.NettyApplicationCallHandler.handleRequest(NettyApplicationCallHandler.kt:43)
	at io.ktor.server.netty.NettyApplicationCallHandler.channelRead(NettyApplicationCallHandler.kt:34)
	at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
	at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:61)
	at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:370)
	at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:164)
	at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:472)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:500)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.ktor.server.netty.EventLoopGroupProxy$Companion.create$lambda-1$lambda-0(NettyApplicationEngine.kt:251)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.lang.Thread.run(Thread.java:748)

트랜잭션 & entity manager 관리

  • JpaTransactionManager 같이 트랜잭션과 entity manager를 관리하는 기능이 필요함.
  • 트랜잭션을 편하게 열고 닫을 수 있는 기능이 필요함.

에러 로깅

  • OurMapExceptionHandler에서 Error 내려주기 전에 에러 로깅하기
  • 센트리 같은 걸로 에러 관리

Hibernate & MySQL 붙이기

  • Hibernate 붙이기
  • MySQL 붙이기
  • Repository 인터페이스 구현
    • Spring Data JPA를 사용하지 않고 편하게 구현할 수 있을까?

에러 핸들링

  1. 비즈니스 로직 상에서 던져진 에러는 500 에러가 아니라 400 에러로 내려줘야 한다.
  2. 어떤 에러가 발생하든 적당한 ErrorDTO를 내려주어 클라이언트가 적절한 대응을 할 수 있게 해야 한다.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.