Skip to content

Commit 2640dd7

Browse files
committed
Feat: ๋ณ‘ํ•ฉ
2 parents 8d4b576 + e79cda3 commit 2640dd7

File tree

23 files changed

+341
-93
lines changed

23 files changed

+341
-93
lines changed
Lines changed: 71 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,102 @@
11
package cmf.commitField.domain.commit.scheduler;
22

33
import cmf.commitField.domain.commit.sinceCommit.service.CommitCacheService;
4-
import cmf.commitField.domain.commit.sinceCommit.service.GithubService;
4+
import cmf.commitField.domain.commit.totalCommit.service.TotalCommitService;
55
import cmf.commitField.domain.redpanda.RedpandaProducer;
66
import cmf.commitField.domain.user.entity.User;
77
import cmf.commitField.domain.user.repository.UserRepository;
88
import lombok.RequiredArgsConstructor;
99
import lombok.extern.slf4j.Slf4j;
10+
import org.springframework.data.redis.core.StringRedisTemplate;
1011
import org.springframework.scheduling.annotation.Scheduled;
1112
import org.springframework.stereotype.Service;
1213

14+
import java.time.LocalDateTime;
1315
import java.util.List;
16+
import java.util.Set;
17+
import java.util.concurrent.TimeUnit;
18+
import java.util.concurrent.atomic.AtomicInteger;
1419

1520
@Slf4j
1621
@Service
1722
@RequiredArgsConstructor
1823
public class CommitScheduler {
19-
private final GithubService githubService;
24+
private final TotalCommitService totalCommitService;
2025
private final CommitCacheService commitCacheService;
2126
private final RedpandaProducer redpandaProducer;
2227
private final UserRepository userRepository;
28+
private final StringRedisTemplate redisTemplate;
29+
private final AtomicInteger counter = new AtomicInteger(0);
2330

2431
@Scheduled(fixedRate = 60000) // 1๋ถ„๋งˆ๋‹ค ์‹คํ–‰
2532
public void updateUserCommits() {
2633
log.info("๐Ÿ” updateUserCommits ์‹คํ–‰์ค‘");
27-
List<User> activeUsers = userRepository.findAll(); // ๐Ÿ’ซ ๋ณ€๊ฒฝ ํ•„์š”, ์ฐจํ›„ active ์ƒํƒœ์ธ user๋งŒ ์ฐพ๊ฒŒ๋” ๋ณ€๊ฒฝํ•ด์•ผ ํ•จ.
34+
int count = counter.incrementAndGet();
2835

29-
log.info("๐Ÿ” Active User Count: {}", activeUsers.size());
36+
if (count % 10 == 0) {
37+
List<User> allUsers = userRepository.findAll();
38+
log.info("๐Ÿ” All User Count: {}", allUsers.size());
3039

31-
for (User user : activeUsers) {
32-
Integer cachedCount = commitCacheService.getCachedCommitCount(user.getUsername());
33-
int newCommitCount = githubService.getUserCommitCount(user.getUsername());
34-
35-
log.info("๐Ÿ” User: {}, Commit Count: {}", user.getUsername(), newCommitCount);
40+
for (User user : allUsers) {
41+
processUserCommit(user);
42+
}
43+
} else {
44+
Set<String> activeUsers = redisTemplate.keys("commit_active:*");
45+
log.info("๐Ÿ” Active User Count: {}", activeUsers.size());
3646

37-
if (cachedCount == null || cachedCount != newCommitCount) { // ๋ณ€ํ™”๊ฐ€ ์žˆ์„ ๋•Œ๋งŒ ์ฒ˜๋ฆฌ
38-
commitCacheService.updateCachedCommitCount(user.getUsername(), newCommitCount);
39-
redpandaProducer.sendCommitUpdate(user.getUsername(), newCommitCount);
47+
for (String key : activeUsers) {
48+
String username = key.replace("commit_active:", "");
49+
User user = userRepository.findByUsername(username).orElse(null);
50+
if (user != null) {
51+
processUserCommit(user);
52+
}
4053
}
4154
}
4255
}
56+
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();
76+
77+
// Redis์—์„œ ์ด์ „ ์ปค๋ฐ‹ ๊ฐœ์ˆ˜ ๊ฐ€์ ธ์˜ค๊ธฐ
78+
Integer previousCommitCount = commitCacheService.getCachedCommitCount(user.getUsername());
79+
long newCommitCount = previousCommitCount == null ? 0 : (currentCommitCount - previousCommitCount);
80+
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๏ธโƒฃ ๋ฉ”์‹œ์ง€ ํ ์ „์†ก
98+
redpandaProducer.sendCommitUpdate(user.getUsername(), newCommitCount);
99+
100+
log.info("โœ… ์ปค๋ฐ‹ ๋ฐ˜์˜ ์™„๋ฃŒ - User: {}, New Commits: {}", user.getUsername(), newCommitCount);
101+
}
43102
}

โ€Žsrc/main/java/cmf/commitField/domain/commit/sinceCommit/entity/CommitHistory.javaโ€Ž

Lines changed: 0 additions & 27 deletions
This file was deleted.

โ€Žsrc/main/java/cmf/commitField/domain/commit/sinceCommit/repositoty/CommitHistoryRepository.javaโ€Ž

Lines changed: 0 additions & 13 deletions
This file was deleted.

โ€Žsrc/main/java/cmf/commitField/domain/commit/sinceCommit/service/CommitCacheService.javaโ€Ž

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,20 @@ public class CommitCacheService {
1414
private final StringRedisTemplate redisTemplate;
1515

1616
public Integer getCachedCommitCount(String username) {
17-
log.info("Redis Template: {}", redisTemplate);
18-
String key = "commit:" + username; // Redis ํ‚ค ์ƒ์„ฑ (ex: commit:hongildong)
17+
String key = "commit_active:" + username; // Redis ํ‚ค ์ƒ์„ฑ (ex: commit:hongildong)
1918
String value = redisTemplate.opsForValue().get(key); // Redis์—์„œ ๊ฐ’ ๊ฐ€์ ธ์˜ค๊ธฐ
20-
return value != null ? Integer.parseInt(value) : null; // ๊ฐ’์ด ์žˆ์œผ๋ฉด ์ •์ˆ˜ ๋ณ€ํ™˜, ์—†์œผ๋ฉด null ๋ฐ˜ํ™˜
19+
20+
if (value != null) {
21+
log.info("โœ… Redis Hit - {} : {}", key, value);
22+
return Integer.parseInt(value);
23+
} else {
24+
log.info("โŒ Redis Miss - {}", key);
25+
return null;
26+
}
2127
}
2228

23-
public void updateCachedCommitCount(String username, int count) {
24-
String key = "commit:" + username;
25-
redisTemplate.opsForValue().set(key, String.valueOf(count), Duration.ofHours(1)); // 1์‹œ๊ฐ„ ์บ์‹ฑ
29+
public void updateCachedCommitCount(String username, long count) {
30+
String key = "commit_active:" + username;
31+
redisTemplate.opsForValue().set(key, String.valueOf(count), Duration.ofHours(3)); // 3์‹œ๊ฐ„ ์บ์‹ฑ
2632
}
2733
}

โ€Žsrc/main/java/cmf/commitField/domain/commit/sinceCommit/service/SinceCommitService.javaโ€Ž

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import cmf.commitField.domain.commit.sinceCommit.dto.CommitAnalysisResponseDto;
44
import cmf.commitField.domain.commit.sinceCommit.dto.SinceCommitResponseDto;
5-
import lombok.AllArgsConstructor;
6-
import lombok.NoArgsConstructor;
75
import lombok.RequiredArgsConstructor;
86
import lombok.extern.slf4j.Slf4j;
97
import org.springframework.beans.factory.annotation.Value;

โ€Žsrc/main/java/cmf/commitField/domain/noti/noti/entity/Noti.javaโ€Ž

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@
33
import cmf.commitField.domain.user.entity.User;
44
import cmf.commitField.global.jpa.BaseEntity;
55
import jakarta.persistence.Entity;
6+
import jakarta.persistence.EnumType;
7+
import jakarta.persistence.Enumerated;
68
import jakarta.persistence.ManyToOne;
79
import lombok.AllArgsConstructor;
810
import lombok.Getter;
911
import lombok.NoArgsConstructor;
1012
import lombok.Setter;
1113
import lombok.experimental.SuperBuilder;
14+
import org.hibernate.annotations.ColumnDefault;
1215

1316
import static lombok.AccessLevel.PROTECTED;
1417

@@ -19,13 +22,17 @@
1922
@Getter
2023
@Setter
2124
public class Noti extends BaseEntity {
25+
@Enumerated(EnumType.STRING)
26+
private NotiType typeCode; // ์•Œ๋ฆผ ํƒ€์ž…
27+
private NotiDetailType type2Code; // ์•Œ๋ฆผ ์„ธ๋ถ€ ํƒ€์ž…
2228
@ManyToOne
23-
private User actor;
24-
@ManyToOne
25-
private User receiver;
26-
private String relTypeCode;
27-
private long relId;
28-
private String typeCode;
29-
private String type2Code;
30-
private boolean read;
29+
private User receiver; // ์•Œ๋ฆผ์„ ๋ฐ›๋Š” ์‚ฌ๋žŒ
30+
@ColumnDefault("false")
31+
private boolean isRead; // ์ฝ์Œ ์ƒํƒœ
32+
private String message; // ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€
33+
34+
// TODO: ์•Œ๋ฆผ์ด ์—ฐ๊ฒฐ๋œ ๊ฐ์ฒด ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€ ๊ณ ๋ฏผ ํ•„์š”.
35+
// private String relTypeCode; // ์•Œ๋ฆผ์ด ์—ฐ๊ฒฐ๋œ ์‹ค์ œ ๊ฐ์ฒด ์œ ํ˜•
36+
// private long relId; // ์•Œ๋ฆผ ๊ฐ์ฒด์˜ Id
37+
3138
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package cmf.commitField.domain.noti.noti.entity;
2+
3+
public enum NotiDetailType {
4+
// ์—…์ 
5+
ACHIEVEMENT_COMPLETED, // ์—…์  ๋‹ฌ์„ฑ
6+
7+
// ์—ฐ์†
8+
STREAK_CONTINUED, // ์—ฐ์† ์ปค๋ฐ‹ ์ด์–ด์ง
9+
STREAK_BROKEN, // ์—ฐ์† ์ปค๋ฐ‹ ๋Š๊น€
10+
11+
// ์‹œ์ฆŒ
12+
SEASON_START // ์‹œ์ฆŒ ์‹œ์ž‘
13+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package cmf.commitField.domain.noti.noti.entity;
2+
3+
import java.util.Map;
4+
5+
public class NotiMessageTemplates {
6+
// ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€ ํ…œํ”Œ๋ฆฟ์„ ์ €์žฅํ•˜๋Š” ๋งต
7+
private static final Map<NotiDetailType, String> TEMPLATES = Map.of(
8+
NotiDetailType.ACHIEVEMENT_COMPLETED, "๐ŸŽ‰ {0}๋‹˜์ด '{1}' ์—…์ ์„ ๋‹ฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค!",
9+
NotiDetailType.STREAK_CONTINUED, "๐Ÿ”ฅ {0}๋‹˜์˜ ์—ฐ์† ์ปค๋ฐ‹์ด {1}์ผ์งธ ์ด์–ด์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค!",
10+
NotiDetailType.STREAK_BROKEN, "๐Ÿ˜ข {0}๋‹˜์˜ ์—ฐ์† ์ปค๋ฐ‹ ๊ธฐ๋ก์ด ๋Š๊ฒผ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ๋ฒˆ์—” ๋” ์˜ค๋ž˜ ์œ ์ง€ํ•ด๋ด์š”!",
11+
NotiDetailType.SEASON_START, "๐Ÿš€ ์ƒˆ๋กœ์šด ์‹œ์ฆŒ '{0}'์ด ์‹œ์ž‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค! ๋žญํ‚น ๊ฒฝ์Ÿ์„ ์ค€๋น„ํ•˜์„ธ์š”!"
12+
);
13+
14+
// ์•Œ๋ฆผ ๋ฉ”์‹œ์ง€ ํ…œํ”Œ๋ฆฟ์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฉ”์„œ๋“œ
15+
public static String getTemplate(NotiDetailType type) {
16+
return TEMPLATES.getOrDefault(type, "์•Œ๋ฆผ ๋ฉ”์‹œ์ง€๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.");
17+
}
18+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package cmf.commitField.domain.noti.noti.entity;
2+
3+
public enum NotiType {
4+
RANK, // ๋žญํ‚น
5+
ACHIEVEMENT, // ์—…์ 
6+
ABSENCE, // ๋ถ€์žฌ
7+
STREAK, // ์—ฐ์†
8+
SEASON, // ์‹œ์ฆŒ
9+
NOTICE // ๊ณต์ง€
10+
}
Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,35 @@
11
package cmf.commitField.domain.noti.noti.eventListener;
22

3+
import cmf.commitField.domain.noti.noti.entity.NotiDetailType;
4+
import cmf.commitField.domain.noti.noti.entity.NotiType;
35
import cmf.commitField.domain.noti.noti.service.NotiService;
6+
import cmf.commitField.global.chat.ChatMessageDto;
7+
import cmf.commitField.global.event.CommitHistoryEvent;
48
import lombok.RequiredArgsConstructor;
9+
import org.springframework.kafka.annotation.KafkaListener;
510
import org.springframework.stereotype.Component;
611

712
@Component
813
@RequiredArgsConstructor
914
public class NotiEventListener {
15+
// ์ด๋ฒคํŠธ๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ ์‹คํ–‰๋˜๋Š” ๋ฉ”์„œ๋“œ
16+
// ๋ฉ”์„œ๋“œ๋ฅผ ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ๋น„๋™๊ธฐ์ ์œผ๋กœ ์‹คํ–‰ํ•˜๋„๋ก ๋งŒ๋“ฆ
1017
private final NotiService notiService;
1118

12-
// public void listenPost(PostCreatedEvent event){
13-
// notiService.postCreated(event.getPost());
14-
// }
15-
//
16-
// public void consume(ChatMessageDto message){
17-
// System.out.println("Consumed message: " + message);
18-
// }
19-
//
20-
// public void consumeChatRoom1DLT(byte[] in){
21-
// String message = new String(in);
22-
// System.out.println("Failed message: " + message);
23-
// }
19+
// ์˜ˆ์‹œ
20+
// CommitHistoryEvent ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด notiService.createCommitStreak() ๋ฉ”์„œ๋“œ๋ฅผ ์‹คํ–‰
21+
public void listenCommitStreak(CommitHistoryEvent event){
22+
notiService.createCommitStreak(event.getUsername(), NotiType.STREAK, NotiDetailType.STREAK_CONTINUED);
23+
}
24+
25+
@KafkaListener(topics = "chat-room-1", groupId = "1")
26+
public void consume(ChatMessageDto message){
27+
System.out.println("Consumed message: " + message);
28+
}
29+
30+
@KafkaListener(topics = "chat-room-1-dlt", groupId = "1")
31+
public void consumeChatRoom1DLT(byte[] in){
32+
String message = new String(in);
33+
System.out.println("Failed message: " + message);
34+
}
2435
}

0 commit comments

Comments
ย (0)