묻고 답해요
158만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결자바 동시성 프로그래밍 [리액티브 프로그래밍 Part.1]
동기 & 논블록킹 질문 드립니다.
안녕하세요 강의 듣다 궁금증이 생겨 질문 드립니다.강의자료 343p 보면 동기 & 논블록킹에 대한 예시 그림이 나오는데요.1) T1이 수행중인 Task4 에서 T2의 Task3, T3의 Task5 의 작업을 기다리고 있어 스레드 T1은 부분적으로 동기처리 된다고 이해했습니다. 이 내용이 맞을까요?2) " Wait and Acknowledge " 부분에서 T1이 T2, T3의 작업결과를 가져와야 다음 작업을 수행할 수 있으므로 동기이면서 Blocking이 발생할 것 같은데요. (ex. Future.get 으로 구현할 경우) 그림만 봐서는 Non-blocking방식인 것 같아 생각해보니, T1이 BusyWaiting방식으로 loop안에서 T1, T2의 완료여부를 체크하는 것 같습니다. 이 내용이 맞을까요? 그렇다면, 만약 Future.get처럼 Block되는 방식의 API를 사용하면 T1은 Task4에서 Non-blocking이 아닌 Blocking된다고 이해해도 될까요?
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI, async, await)
교안 제공은 안되나요?
교안 제공은 안되나요?
-
미해결자바 동시성 프로그래밍 [리액티브 프로그래밍 Part.1]
AtomicIntegerGetAndUpdateExample 예시가 부자연스럽습니다.
AtomicInteger의 getAndUpdate가 람다를 적용하기 전의 값을 반환하므로,해당 메소드의 반환 값을 출금 후 잔고가 아니고, 출금 전 잔고로 표현하는 것이 의미가 맞습니다. 추가로 출금 전의 잔고가 출금액 보다 작아야 잔고 부족으로 출금이 실패한다고 표현해야 자연스러운 것 같습니다. 해당 예시를 다음과 같이 수정했습니다.// main function for (int i = 0; i < 5; i++) { new Thread(() -> { int withdrawalAmount = 500; // 출금액 int beforeUpdatedBalance = accountBalance.getAndUpdate(balance -> { if (balance >= withdrawalAmount) { return balance - withdrawalAmount; // 출금 성공 } else { return balance; // 출금 실패 } }); if (beforeUpdatedBalance < withdrawalAmount) { System.out.println(Thread.currentThread().getName() + " : 잔고 부족으로 출금 실패"); } else { System.out.println(Thread.currentThread().getName() + " : 출금 전 잔고: " + beforeUpdatedBalance); } }).start(); } 강의 잘 듣고 있습니다. 감사합니다 🙂
-
미해결자바 동시성 프로그래밍 [리액티브 프로그래밍 Part.1]
ReentrantLock.lockInterruptibly() 질문
먼저 강의 잘 듣고 있습니다. 강의 자료 202쪽에 보면 아래 그림과 같이 ReentrantLock.lockInterruptibly() 예제 코드가 작성되어 있는데요. 이 코드를 강의 소스코드 (LockInterruptiblyExample.java) 에 적용해 보았습니다. 적용한 코드는 아래와 같습니다. public class LockInterruptiblyExample { public static void main(String[] args) { Lock lock = new ReentrantLock(); Thread thread1 = new Thread(() -> { try { lock.lockInterruptibly(); // 락을 시도하며, 인터럽트가 들어오면 중단 System.out.println("스레드 1이 락을 획득했습니다"); } catch (InterruptedException e) { System.out.println("스레드 1이 인터럽트를 받았습니다"); } finally { lock.unlock(); System.out.println("스레드 1이 락을 해제했습니다"); } }); Thread thread2 = new Thread(() -> { try { lock.lockInterruptibly(); // 락을 시도하며, 인터럽트가 들어오면 중단 try { System.out.println("스레드 2가 락을 획득했습니다"); } finally { lock.unlock(); System.out.println("스레드 2가 락을 해제했습니다"); } } catch (InterruptedException e) { System.out.println("스레드 2가 인터럽트를 받았습니다"); } }); thread1.start(); thread2.start(); thread1.interrupt(); // thread2.interrupt(); try { Thread.sleep(500); thread1.join(); thread2.join(); } catch (InterruptedException e) { e.printStackTrace(); } } } 이 코드를 실행했을 때, 아래 이미지와 같이 IllegalMonitorStateException 이 발생했는데요. 아마 try ~ catch ~ finally 블록에 의한 문제가 아닐까 싶습니다. 이 부분이 어떻게 동작하여 오류가 발생한 건지 궁금한데, 답변 해주시면 감사하겠습니다.
-
해결됨파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI, async, await)
TypeError: field Config is defined without type annotation
'FastAPI + MongoDB ODM 셋업' 강의 중 book.py 파일을 만든 뒤 서버를 실행할 때 아래와 같은 에러 메시지가 노출됩니다. TypeError: field Config is defined without type annotation Config에 type annotation이 정의되지 않았다고 하는데, 타입을 정의하거나 클래스 이름을 바꿔보는 등의 방법을 적용해보아도 같은 에러코드가 노출되고 있어 문의드립니다. 제가 사용하고 있는 환경의 python은 3.8버전이며, odmantic 등 라이브러리는 최신 버전을 사용하고 있습니다.
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
synchronized 오류
@Service public class StockService { private final StockRepository stockRepository; public StockService(StockRepository stockRepository) { this.stockRepository = stockRepository; } // @Transactional public synchronized void decrease(Long id, Long quantity) { // Stock 조회 Stock stock = stockRepository.findById(id) .orElseThrow(EntityNotFoundException::new); // 재고 감소 stock.decrease(quantity); // 갱신된 값을 저장 // stockRepository.save(stock); } }안녕하십니까! 제가 알기로는 영속성 컨텍스트의 변경감지 기술로 인해서 별도의 save 메서드를 실행하지 않아도 값이 update 되는 걸로 알고있는데 그럴 경우 @Transactional를 제거하면 영속성 컨텍스트로 관리하지 않기 때문에 테스트를 진행하면 오류가 발생하고있습니다ㅠㅠ 혹시 제가 잘못된 지식을 갖고있는건가요?ㅠ
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
LettuceLock 에러
안녕하세요.올려주신 강의를 보고 따라하다가 에러가 발생하여 질문드립니다.모든 테스트는 정상으로 떨어지나, LettuceLock 테스트만 에러가 발생을 하네요...제가 디버깅 했을 때는 public Boolean lock(Long key) { return redisTemplate .opsForValue() .setIfAbsent(generateKey(key), "lock", Duration.ofMillis(3_000)); }해당 부분이 키를 갖고 오지 못하는 거 같은데, 해결 방법이 있을까요??
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
RedissonLock에서 질문드립니다.
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.안녕하세요. 강의 열심히 듣고 있습니다. Redisson 관련 실습을 진행하고 있는데, 시간을 변경해도 계속 test results가 fail이 뜨고 있습니다. 관련 원인을 모르겠습니다. github에서 코드를 복붙해봐도 똑같아서 문의드립니다. 어떤게 오류인지도 잘 모르겠어서 질문드립니다 감사합니다.org.opentest4j.AssertionFailedError: expected: <0> but was: <100> at org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:151) at org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:132) at org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:197) at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:182) at org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:177) at org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:639) at com.example.stock.facade.RedissonLockStockFacadeTest.동시에_100개의요청(RedissonLockStockFacadeTest.java:58) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
-
미해결고수가 되는 파이썬 : 동시성과 병렬성 문법 배우기 Feat. 멀티스레딩 vs 멀티프로세싱 (Inflearn Original)
python gil 삭제
https://www.itworld.co.kr/news/302737 안녕하세요! 파이썬 공부를 위해 강사님의 강의를 열심히 듣고 있는 학습자입니다.다름이 아니라 Python GIL에 대한 공부를 더 하고싶어 검색을 하던 중 해당 기사를 접하게 되어서 Python's GIL 강의에 내용에서 달라지는 부분이 있는지 궁금합니다!좋은 강의를 제공해주셔서 정말 감사합니다!
-
해결됨실전! Django 활용
python manage.py showmigrations 문제
안녕하세요.실습 진행 중에 처음부터 잘 안돼서 메세지 드립니다. python magage.py showmigration 하고 migrate 후에 sqllite 파일 삭제했습니다.다시 prostresql 도커 적용하고 그 후부터 에러가 나네요.python manage.py showmigrationsadmin[X] 0001_initial[X] 0002_logentry_remove_auto_add[X] 0003_logentry_add_action_flag_choicesauth[X] 0001_initial[X] 0002_alter_permission_name_max_length[X] 0003_alter_user_email_max_length[X] 0004_alter_user_username_opts[X] 0005_alter_user_last_login_null[X] 0006_require_contenttypes_0002[X] 0007_alter_validators_add_error_messages[X] 0008_alter_user_username_max_length[X] 0009_alter_user_last_name_max_length[X] 0010_alter_group_name_max_length[X] 0011_update_proxy_permissions[X] 0012_alter_user_first_name_max_lengthcontenttypes[X] 0001_initial[X] 0002_remove_content_type_namesessions[X] 0001_initial어떻게 하면 좋을까요?장고 프로젝트 설치도 해보고 도커도 지워보고 했는데 잘 안돼서 메세지 드립니다. python manage.py makemigrationsno Chages detected python manage.py migrateOperations to perform:Apply all migrations: admin, auth, contenttypes, sessionsRunning migrations:No migrations to apply. 아래의 setting 정보로 database 접속도 잘됩니다.DATABASES = {"default": {"ENGINE": "django.db.backends.postgresql_psycopg2","NAME": "goodpang","USER": "goodpang","PASSWORD": "goodpang","HOST": "127.0.0.1","PORT": "5433",}}
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI, async, await)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. # app 폴더 아래 main.py @app.post("/collect", response_class=HTMLResponse) async def collect(request: Request): brandlist = BrandList() brands = await brandlist.run() oy_models = [] for brand in brands: oy_model = BrandListModel( code=brand["code"], brand=brand["brand"], collection_time=brand["time"], status=brand["status"], ) oy_models.append(oy_model) await mongodb.engine.save_all(oy_models) return templates.TemplateResponse( "./index.html", {"request": request, "title": "수집기", "brands": brands}, ) # app 폴더 아래 spcrper.py class BrandList: URL = "https://www.#######.co.kr" def unit_url(self): url = f"{self.URL}/store/main/getBrandList.do" return url async def fetch(self): async with aiohttp.ClientSession() as session: async with session.get(self.unit_url()) as response: soup = BeautifulSoup(await response.text(), "html.parser") area_info = soup.select("a[data-ref-onlbrndcd]") branddics = [] for info in area_info: code = info["data-ref-onlbrndcd"] name = info.text collectiontime = date.today() item = [i["code"] for i in branddics] if code in item: pass else: branddic = { "code": f"{code}", "brand": f"{name}", "time": f"{collectiontime}", "status": "Old", } branddics.append(branddic) await session.close() return branddics def run(self): return asyncio.run(self.fetch()) 안녕하세요. 강사님. scraper.py 는 terminal에서 값을 잘 가져오고 있습니다. server.py에서 구동 시, 아래와 같은 error가 나오는데 원인을 찾지 못해서요 ㅠ RuntimeError: asyncio.run() cannot be called from a running event loopC:\Users\user\Desktop\Project_Scraper\venv\Lib\site-packages\uvicorn\protocols\http\httptools_impl.py👎 RuntimeWarning: coroutine 'BrandList.fetch' was never awaitedRuntimeWarning: Enable tracemalloc to get the object allocation traceback 코드 리뷰 좀 부탁드리겠습니다.
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
싱글톤에서 ConcurrentHashMap을 쓰더라도 map객체가 공유됩니다...
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]@RestController @RequestMapping("/test") public class TestController { private Map<String, Object> map = new ConcurrentHashMap(); @ModelAttribute private void data() { map.put("data", "abcd"); } @GetMapping("/data1") public Response<Map<String,Object>> datas1() throws InterruptedException { map.remove("api"); synchronized (map) { map.put("api", "efgh"); } Thread.sleep(3000); return Response.success(map); } @GetMapping("/data2") public Response<Map<String,Object>> datas2() { map.remove("api"); synchronized (map) { map.put("api", "ijkl"); } return Response.success(map); } } 위와같이 @ModelAttribute를 메소드레벨에 선언하여 AOP의 안티패턴 느낌으로 사용해보려고 로직을 구현해봤는데싱글톤 동시성 문제를 고려해서 ConcurrentHashMap을 전역변수로 지정하고 사용하는데도data1 요청 후 3초가 지나기전 data2 요청을 하니data1 요청 결과가 data2 요청 결과로 찍힙니다.data1 작업이 종료 되기전(3초이내)에 data2 작업으로 map객체를 초기화 해버리는걸로 보아 map객체가 공유가 되고 있다는것인데...ConcurrentHashmap으로 이러한 동시성 문제가 해결되지 않는 이유가 뭐고,,, ConcurrentHashmap을 사용하여 처리할만한 적절한 코드가 있을까요?추가적으로 private ThreadLocal<Map<String, Object>> map = ThreadLocal.withInitial(ConcurrentHashMap::new); @ModelAttribute private void data() { map.get().put("data", "abcd"); } @GetMapping("/data1") public Response<Map<String,Object>> datas1() throws InterruptedException { map.get().put("api1", "efgh"); Thread.sleep(3000); return Response.success(map.get()); } @GetMapping("/data2") public Response<Map<String,Object>> datas2() { map.get().put("api2", "ijkl"); return Response.success(map.get()); }위와같이 ThreadLocal을 활용하면 이 문제가 해결되긴 합니다.가급적 AI 말고 우리의 리빙레전드 영한이형님께서 직접 답변 해주시길 부탁드리겠습니다 ㅠㅠ
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
Pessimitic Lock 과 Optimitic Lock 질문
안녕하세요, 강의를 듣다가 몇가지 질문이 생겼습니다.1. Pessimitic Lock와 Optimitic Lock 는 select 구문(@Query("select ...) 나 find 쿼리메서드)에서만 @Lock을 적용하는거라고 이해하면 될까요?2. Pessimitic Lock 과 Optimitic Lock 의 벌크 수정 쿼리는 어떻게 처리가 되는건가요? 2-1. Pessimitic Lock 은 select 절로 데이터를 가져오지 않는다면 어떻게 벌크 수정이 되는건가요?2-2. Optimitic Lock 은 벌크 연산에서 직접 버전을 수정하는게 맞을까요?좋은 강의 감사합니다.
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI, async, await)
jinja2templates
수업대로 127.0.0.1:8000/items/{id} 를 넣었는데starlette.routing.NoMatchFound: No route exists for name "static" and params "path".internal Server Error 가 나옵니다 ㅠBASE_DIR, directory 모두 수업대로 다 입력했습니다. 구글링을 해도 방법을 찾질 못해서요.
-
해결됨재고시스템으로 알아보는 동시성이슈 해결방법
Optimistic Lock 버전 관리 질문
버전 관리를 통하여 동시성을 피할수 있다고 하셨는데, 서로 다른 서버에서 동시에 version = 1 인 데이터룰 얻고, 동시에 stock = stock + 1, version = 2 로 업데이트 치면 optimistic lock 또한 동시성이 발생할 수 있는 것 아닌가요? 강의에서는 version = 1 인 데이터를 동시에 얻지만 업데이트는 순차적으로 하는 표만 보여주셔서 헷갈려요. 순차적으로 할 수 밖에 없는 메커니즘이라면 그 부분을 설명해주셨으면 좋겠습니다.
-
미해결자바 동시성 프로그래밍 [리액티브 프로그래밍 Part.1]
동기화와 CPU 관계 불일치 흐름도
무릎을 탁치는 명강의였습니다. 감사합니다.
-
미해결자바 동시성 프로그래밍 [리액티브 프로그래밍 Part.1]
예제 transfer 메서드
안녕하세요, 강사님. 강의 40분에 나오는 예제의 transfer메서드에서 호출하는 withdraw, deposit 메소드는 이미 synchronized 블록 동기화가 되어있는데 왜 또 호출전에 synchronized 블록 동기화 구문을 작성하는지 궁금합니다. 감사합니다.
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
낙관적 락 무한루프 질문
강사님의 강의를 보며 현재 제 프로젝트에 낙관적 락을 적용시켜 보았습니다.구현하고자 하는 서비스는 쿠폰 발급 서비스이며, DB 구조는user 1 : N user_coupon N : 1 coupon 입니다. @Transactional public void issueCoupon(CouponIssueParam param, User user) { // 쿠폰 조회 Coupon coupon = getCoupon(param.getCouponId()); // 쿠폰 발급 UserCoupon userCoupon = UserCoupon.CreateUserCoupon(coupon, user); userCouponQueryService.saveUserCoupon(userCoupon); }public static UserCoupon CreateUserCoupon(Coupon coupon, User user) { // 쿠폰 검증 coupon.validateCoupon(); // 재고 감소 coupon.decreaseQuantity(); return UserCoupon.builder() .coupon(coupon) .user(user) .build(); }위 코드와 같이 유저가 특정 쿠폰 Id 를 통해 쿠폰 발급 요청을 하고, 중간 테이블에 관계가 매핑됨으로써 쿠폰 발급이 이루어집니다. public void validateCoupon() { if(this.stockStatus.equals(StockStatus.OUT_OF_STOCK)) throw new IllegalArgumentException("쿠폰이 매진되었습니다."); if(this.expiredAt.isBefore(LocalDateTime.now())) throw new IllegalArgumentException("쿠폰이 만료되었습니다."); }이때 user_coupon 생성 전 쿠폰의 매진 및 만료 상태에 따라 예외를 던지는 검증 메서드가 존재합니다. public void decreaseQuantity() { this.remainQuantity = this.remainQuantity - 1; if(this.remainQuantity <= 0){ this.stockStatus = StockStatus.OUT_OF_STOCK; } }추가로 쿠폰 내부에 재고가 감소하는 메서드가 존재하며 0에 다다를 경우 상태값을 변경해줍니다. 이때 동시성 이슈가 발생하는 이유는 user_coupon 을 insert 하면서, 부모 테이블인 coupon 의 재고를 update 하는 과정에서 발생하는 것으로 파악했습니다. 이에 쿠폰 발급 초기에 coupon 을 조회할 때 @Lock(LockModeType.OPTIMISTIC) @Query("select c from Coupon c where c.id = :couponId and c.isDeleted = false") Optional<Coupon> findOneCouponByCouponId(@Param("couponId") Long couponId);이처럼 낙관적 락 어노테이션을 달아주었으며 @Component @RequiredArgsConstructor public class OptimisticLockFacade { private final CouponService couponService; public void issueCoupon(CouponIssueParam param, User user) throws InterruptedException { while (true) { try { couponService.issueCoupon(param, user); break; } catch (Exception e) { Thread.sleep(50); // 재시도 전 잠시 대기 } } } }위와 같이 퍼사드 클래스를 생성하였습니다. @Test @DisplayName("쿠폰 여러 명 발급") void 쿠폰_여러_명_발급() throws InterruptedException { int threadCount = 1000; ExecutorService executorService = Executors.newFixedThreadPool(32); CountDownLatch latch = new CountDownLatch(threadCount); for (int i = 0; i < threadCount; i++) { final int threadNumber = i + 1; int key = i; executorService.submit(() -> { try { optimisticLockFacade.issueCoupon(param, users.get(key)); System.out.println("Thread " + threadNumber + " - 성공"); } catch (PessimisticLockingFailureException e) { System.out.println("Thread " + threadNumber + " - 락 충돌 감지"); } catch (Exception e) { System.out.println("Thread " + threadNumber + " - " + e.getMessage()); } finally { latch.countDown(); } }); } latch.await(); executorService.shutdown(); Long count = userCouponRepository.countByCouponId(param.getCouponId()); assertThat(count).isEqualTo(100); } 쿠폰의 재고가 100개며, 1,000 명의 유저가 32개의 스레드 환경에서 쿠폰 발급을 요청할 때 예상되는 발급 쿠폰 수는 100개가 되어야 합니다. 이렇게 낙관적 락을 적용하여 테스트를 수행하니 무한 루프에 빠지게 되었습니다.무한루프로 인해 테스트가 종료되지 않자, 강제적으로 정지 시킨 후 DB 를 확인했는데 쿠폰의 수는 예상한 대로 100개가 생성된 것을 확인할 수 있었습니다. 그런데 왜 메서드가 종료되지 않고 무한루프가 돌아간 것인지 이유를 모르겠습니다. public void issueCoupon(CouponIssueParam param, User user) throws InterruptedException { while (true) { try { couponService.issueCoupon(param, user); break; } catch (IllegalArgumentException e) { System.out.println("쿠폰 발급 실패: " + e.getMessage()); break; } catch (Exception e) { Thread.sleep(50); // 재시도 전 잠시 대기 } } } 혹시나 하여, 쿠폰 발급 로직에 쿠폰이 매진이 될 경우 예외를 던지는 검증 메서드가 존재했고 이에 퍼사드 클래스에서 해당 예외를 잡아내면 루프를 빠져나오게 설정했습니다. 이렇게 구현하니 테스트는 성공적으로 통과하였습니다. 현재 제가 구현한 서비스 구성에서는 이런식으로 접근하는 게 맞는 걸까요 ?
-
미해결운영체제 공룡책 강의
강의 ppt 제공
강의 ppt는 어디서 다운 받을 수 있나요?
-
미해결파이썬 동시성 프로그래밍 : 데이터 수집부터 웹 개발까지 (feat. FastAPI, async, await)
몽고DB 설정 관련 질문
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. FastAPI + MongoDB : MongoDB ODM 셋업 강의를 듣고 있는데 궁금한 점이 생겨서요!섹션4에서 몽고DB 데이터베이스 설정할 때 "nest"로 프로젝트명을 설정하여 해당 url도 받고 했었는데 섹션5에서는 프로젝트명도 바뀌고 url도 바껴서요. 제가 "nest" 설정했던 것처럼 새로 "fastapi-pj" 프로젝트 만들어서 url 받고 secret.json에 넣으면 될까요?