1414import java .time .LocalDateTime ;
1515import java .util .List ;
1616import java .util .Set ;
17+ import java .util .concurrent .TimeUnit ;
1718import java .util .concurrent .atomic .AtomicInteger ;
1819
1920@ Slf4j
@@ -25,77 +26,77 @@ public class CommitScheduler {
2526 private final RedpandaProducer redpandaProducer ;
2627 private final UserRepository userRepository ;
2728 private final StringRedisTemplate redisTemplate ;
28- private final AtomicInteger counter = new AtomicInteger (0 ); // 카운터 변수
29+ private final AtomicInteger counter = new AtomicInteger (0 );
30+
2931 @ Scheduled (fixedRate = 60000 ) // 1분마다 실행
3032 public void updateUserCommits () {
31- // 최근 3시간 이내에 커밋 기록이 없는 유저는 주기적으로 검사하지 않고, 10분에 한 번씩 검사함 -> 전체 검사
32- // 최근 3시간 이내에 커밋 기록이 있는 유저는 1분에 한번씩 검사함. -> 일부 검사
33- // Redis에 커밋 기록이 있는 유저를 기록하고, 이 유저들에 한해서만 API를 검색함
34- // Redis에 저장되지 않은 유저는 1시간에 한 번씩 검사하는 메소드를 실행
35- // 검사를 실행한 후, 커밋 기록이 갱신된 유저는 반영 후 Redis에 3시간동안 지속되게끔 값을 생성해준다.
3633 log .info ("🔍 updateUserCommits 실행중" );
37- int count = counter .incrementAndGet (); // 실행 횟수 증가
34+ int count = counter .incrementAndGet ();
3835
3936 if (count % 10 == 0 ) {
40- // 🔹 10분마다 전체 유저 검색
4137 List <User > allUsers = userRepository .findAll ();
4238 log .info ("🔍 All User Count: {}" , allUsers .size ());
4339
4440 for (User user : allUsers ) {
45- // 🔹 API에서 해당 유저의 최근 커밋 개수 가져오기
46- long newCommitCount = totalCommitService .getSeasonCommits (
47- user .getUsername (),
48- user .getLastCommitted (),
49- LocalDateTime .now ()
50- ).getTotalCommitContributions ();
51-
52- if (newCommitCount > 0 ) {
53- // 🔹 커밋 기록이 있으면 DB, Redis, 메시지 큐 반영
54- updateCommitData (user , newCommitCount );
55- }
56-
57- log .info ("🔍 User: {}, Commit Count: {}" , user .getUsername (), newCommitCount );
41+ processUserCommit (user );
5842 }
5943 } else {
60- // 🔹 1분마다 Redis에 저장된 유저만 검색
61- Set <String > activeUsers = redisTemplate .keys ("commit_active:*" ); // Redis에서 저장된 유저 키 가져오기
44+ Set <String > activeUsers = redisTemplate .keys ("commit_active:*" );
6245 log .info ("🔍 Active User Count: {}" , activeUsers .size ());
6346
6447 for (String key : activeUsers ) {
65- String username = key .replace ("commit_active:" , "" ); // Redis 키에서 유저명 추출
48+ String username = key .replace ("commit_active:" , "" );
6649 User user = userRepository .findByUsername (username ).orElse (null );
67- if (user == null ) continue ;
68-
69- // 🔹 API에서 해당 유저의 최근 커밋 개수 가져오기
70- long newCommitCount = totalCommitService .getSeasonCommits (
71- user .getUsername (),
72- user .getLastCommitted (),
73- LocalDateTime .now ()
74- ).getTotalCommitContributions ();
75-
76- if (newCommitCount > 0 ) {
77- // 🔹 커밋 기록이 있으면 DB, Redis, 메시지 큐 반영
78- updateCommitData (user , newCommitCount );
50+ if (user != null ) {
51+ processUserCommit (user );
7952 }
80-
81- log .info ("🔍 Active User: {}, Commit Count: {}" , user .getUsername (), newCommitCount );
8253 }
8354 }
8455 }
8556
86- // 🔹 커밋 기록이 있으면 DB + Redis + 메시지 큐 반영하는 메소드
87- private void updateCommitData (User user , long newCommitCount ) {
88- // 1️⃣ DB의 lastCommitted 갱신
89- user .setLastCommitted (LocalDateTime .now ());
90- userRepository .save (user );
57+ // 🔹 유저 커밋 검사 및 반영
58+ private void processUserCommit (User user ) {
59+ // Redis에서 lastCommitted 값 가져오기
60+ String redisKey = "commit_last:" + user .getUsername ();
61+ String lastCommittedStr = redisTemplate .opsForValue ().get (redisKey );
62+ LocalDateTime lastCommitted ;
63+ if (lastCommittedStr != null ){
64+ lastCommitted =LocalDateTime .parse (lastCommittedStr );
65+ }else {
66+ user .setLastCommitted (LocalDateTime .now ()); // 레디스에 저장되어있지 않았다면 등록 시점에 lastCommitted를 갱신
67+ lastCommitted =user .getLastCommitted (); // Redis에 없으면 DB값 사용;
68+ }
69+
70+ // 현재 커밋 개수 조회
71+ long currentCommitCount = totalCommitService .getSeasonCommits (
72+ user .getUsername (),
73+ lastCommitted , // 🚀 Redis에 저장된 lastCommitted 기준으로 조회
74+ LocalDateTime .now ()
75+ ).getTotalCommitContributions ();
9176
92- // 2️⃣ Redis에 갱신 (3시간 동안 유지)
93- commitCacheService .updateCachedCommitCount (user .getUsername (), newCommitCount );
77+ // Redis에서 이전 커밋 개수 가져오기
78+ Integer previousCommitCount = commitCacheService .getCachedCommitCount (user .getUsername ());
79+ long newCommitCount = previousCommitCount == null ? 0 : (currentCommitCount - previousCommitCount );
9480
95- // 3️⃣ 레드판다 메시지 전송
81+ if (newCommitCount > 0 ) {
82+ updateCommitData (user , currentCommitCount , newCommitCount );
83+ }
84+
85+ log .info ("🔍 User: {}, New Commits: {}, Total Commits: {}" , user .getUsername (), newCommitCount , currentCommitCount );
86+ }
87+
88+ // 🔹 새 커밋이 있으면 데이터 업데이트
89+ private void updateCommitData (User user , long currentCommitCount , long newCommitCount ) {
90+ // 1️⃣ Redis에 lastCommitted 업데이트 (3시간 TTL)
91+ String redisKey = "commit_last:" + user .getUsername ();
92+ redisTemplate .opsForValue ().set (redisKey , LocalDateTime .now ().toString (), 3 , TimeUnit .HOURS );
93+
94+ // 2️⃣ Redis에 최신 커밋 개수 저장 (3시간 동안 유지)
95+ commitCacheService .updateCachedCommitCount (user .getUsername (), currentCommitCount );
96+
97+ // 3️⃣ 메시지 큐 전송
9698 redpandaProducer .sendCommitUpdate (user .getUsername (), newCommitCount );
9799
98100 log .info ("✅ 커밋 반영 완료 - User: {}, New Commits: {}" , user .getUsername (), newCommitCount );
99101 }
100-
101102}
0 commit comments