본문 바로가기
Projects

[Slack AI Bot] Redis로 부재 감지 시간 조정

by hxxyeoniii 2025. 12. 7.

Redis를 사용해 슬랙 사용자의 활동을 추적하는 서비스 생성

 
주요 필드

  • KEY_PREFIX = "activity:" -> Redis 키 접두사
  • ttlHours = 4 -> 데이터 자동 삭제 시간(4시간)
  • redisTemplate -> Redis 작업용
  • objectMapper -> Java, JSON 변환

 
recordActivity(userId, channelId)

    /**
     * 사용자 활동 기록 -> 메시지 받을 때 마다 실행
     * @param userId 사용자 ID
     * @param channelId 채널 ID
     */
    public void recordActivity(String userId, String channelId) {
        String key = createKey(channelId, userId);

        try {
            UserActivity activity = getUserActivity(userId, channelId)
                    .orElse(new UserActivity(userId, channelId));

            activity.updateActivity(); // 활동 시간 업데이트

            // Redis에 JSON으로 저장
            String json = objectMapper.writeValueAsString(activity);
            redisTemplate.opsForValue().set(key, json);

            // TTL 설정 - ttlHours 시간 후 자동 삭제
            redisTemplate.expire(key, ttlHours, TimeUnit.HOURS);

            logger.debug("활동 기록 - User: {}, Channel: {}, TTL: {}h",
                    userId, channelId, ttlHours);

        } catch(JsonProcessingException e) {
            logger.error("활동 기록 실패 - JSON 직렬화 오류", e);
            throw new RuntimeException("활동 기록 실패", e);
        }
    }

-> Redis에서 기존 데이터 조회
-> lastActivityTime을 현재 시간으로 업데이트
-> JSON 변환 후 Redis 저장
-> TTL은 4시간으로 설정
 
 
 
findAllAbsentUsers(absenceHours) : 우선 2분 설정

    /**
     * 모든 채널에서 지정 시간 이상 부재한 사용자 찾기
     */
    public List<UserActivity> findAllAbsentUsers(int absenceHours) {
        String pattern = KEY_PREFIX + "*";
        Set<String> keys = redisTemplate.keys(pattern);

        if (keys == null || keys.isEmpty()) {
            return Collections.emptyList();
        }

        return getActivitiesByKeys(keys).stream()
                .filter(activity -> activity.isAbsentForMinutes(2)) // TODO : 테스트용 2분 설정
                // .filter(activity -> activity.isAbsentForHours(absenceHours))
                .collect(Collectors.toList());
    }

-> 스케줄러가 1분마다 실행하며 호출 중
 
 
 
updateActivity(activity)

public void updateActivity(UserActivity activity) {
        String key = KEY_PREFIX + activity.getChannelId() + ":" + activity.getUserId();

        try {
            String json = objectMapper.writeValueAsString(activity);
            redisTemplate.opsForValue().set(key, json);

            logger.info("활동 업데이트 완료 - User: {}, Channel: {}",
                    activity.getUserId(), activity.getChannelId());

        } catch (JsonProcessingException e) {
            logger.error("활동 업데이트 실패", e);
        }
    }

-> UserActivity 객체 Redis에 업데이트
-> absent 상태 true로


전체 흐름 정리

1. 메시지 전송
   -> recordActivity()
   -> Redis에 저장
 
2. 스케줄러(1분마다)
   -> findAllAbsentUsers(2)
 
3. DM 전송 후
   -> activity.setAbsent(true)
   -> Reids 업데이트(absent : true)


테스트 : 사용자 부재 감지 기준을 2분으로 설정해두고, 디엠 전송이 제대로 동작하는지 확인

12:37 메시지 전송

 
 
 
2분 부재 후 DM 전송된 것 확인

 

 

 

DM 전송 보다는 채널에 봇이 메시지를 전달하는 것이 더 자연스러울 것 같아 수정

* TODO : "2분 부재중이십니당 !" 메시지 대신, open AI의 요약본 전달

 

 
 
레디스 접속

 

 


레디스에 저장된 값 확인
absent : false -> DM 전송 후 -> absent : true로 업데이트