[Event] Spring Event ๋„์ž… ์‹œ ํŠธ๋žœ์žญ์…˜ ์ฒ˜๋ฆฌ์— ๋Œ€ํ•œ ๊ณ ๋ฏผ

1. ์„œ๋ก 

์ „ ๊ฒŒ์‹œ๊ธ€์—์„œ Spring Event๋กœ ์˜์กด์„ฑ์„ ๊ฐœ์„ ํ•˜๋Š” ๋ฒ•์„ ๋‹ค๋ค„๋ณด์•˜๋‹ค. ํ•˜์ง€๋งŒ ํ•œ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์ฒ˜๋ฆฌํ•˜๋˜ ๊ฒƒ๋“ค์ด ํฉ์–ด์ง€๋ฉด์„œ ๋ฌธ์ œ๋˜๋Š” ๋ถ€๋ถ„๋„ ์žˆ๋‹ค. ์ด๋ฒˆ์—” ๊ทธ ๋ถ€๋ถ„์„ ๊นŠ๊ฒŒ ๋‹ค๋ค„๋ณผ ์ƒ๊ฐ์ด๋‹ค.

 

Event๋ฅผ ์ ์šฉํ•˜๊ธฐ ์ „ ์ฝ”๋“œ์™€ ํ›„ ์ฝ”๋“œ๋ฅผ ๋จผ์ € ์‚ดํŽด๋ณด๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

 

- ์ ์šฉ ์ „

@Service
@RequiredArgsConstructor
public class MemberService {

    private final AlarmService alarmService;
    private final AlimTalkService alimTalkService;

    public void register(String name) {
        // ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ ๋กœ์ง
        System.out.println("ํšŒ์› ์ถ”๊ฐ€ ์™„๋ฃŒ");

        // ๊ฐ€์ž… ์ถ•ํ•˜ ํ‘ธ์‹œ ์•Œ๋ฆผ
        alarmService.send(name);

        // ์นด์นด์˜ค ์•Œ๋ฆผํ†ก ์ „์†ก
        alimTalkService.send(name);
    }
}

 

์œ„ ๋กœ์ง์€ ํ•ต์‹ฌ ๋กœ์ง๊ณผ ๋ถ€๊ฐ€์ ์ธ ๋กœ์ง์ด ๋ฌถ์—ฌ์žˆ์–ด ํ•œ๋ˆˆ์— ๋ณด๊ธฐ ์–ด๋ ค์šธ ๋ฟ๋”๋Ÿฌ ์˜์กด์„ฑ์ด ๋†’์•„ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ต๋‹ค. 

์œ„์˜ ์˜ˆ์ œ๋ฅผ ์ •๋ฆฌํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ํ‘œํ˜„ํ•˜๊ณ  ์žˆ๋‹ค. 

 

  • ํšŒ์›๊ฐ€์ž… ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•  ๋•Œ
    • ๊ฐ€์ž… ์ถ•ํ•˜ ํ‘ธ์‹œ ์•Œ๋ฆผ
    • ์นด์นด์˜ค ์•Œ๋ฆผํ†ก ์ „์†ก

 

- ์ ์šฉ ํ›„

@Service
@RequiredArgsConstructor
@Transactional
public class MemberService {

    private final ApplicationEventPublisher publisher;

    public void register(String name) {
        // ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ ๋กœ์ง
        System.out.println("ํšŒ์› ์ถ”๊ฐ€ ์™„๋ฃŒ");

        // ์ด๋ฒคํŠธ ๋“ฑ๋ก
        publisher.publishEvent(new RegisteredEvent(name));
    }
}


@Component
@RequiredArgsConstructor
public class SmsEventHandler {

    private final AlarmService alarmService;
    private final AlimTalkService alimTalkService;

    @Async
    @EventListener
    public void sendFCM(RegisteredEvent event) throws InterruptedException {
        alarmService.send(event.getName());
    }
    
    @Async
    @EventListener
    public void sendAlimTalk(RegisteredEvent event) throws Exception {
        alimTalkService.send(event.getName());
    }
}


@Service
@RequiredArgsConstructor
@Transactional
public class AlarmService {
    private final AlarmRepository alarmRepository;
    public void send(String name) throws InterruptedException {
        alarmRepository.save(Alarm.builder().createdAt(LocalDateTime.now()).build());
        System.out.println(name + "์—๊ฒŒ push ์•Œ๋ฆผ ๋ฐœ์†ก");
    }
}


@Service
@Transactional
public class AlimTalkService {
    public void send(String name) throws Exception {
        Thread.sleep(3000); // 3์ดˆ sleep
        System.out.println(name + "์—๊ฒŒ ์•Œ๋ฆผํ†ก ๋ฐœ์†ก");
        throw new Exception("์—๋Ÿฌ ๋ฐœ์ƒ");
    }
}

 

์œ„ ์ฝ”๋“œ์—์„œ ๋งŒ์•ฝ ํšŒ์›์ด ์ €์žฅ๋˜๋˜ ์ค‘ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋˜ ๋กœ์ง๋“ค์€ ์–ด๋–ป๊ฒŒ๋ ๊นŒ?? 

Async๋ฅผ ์‚ฌ์šฉํ–ˆ๊ณ  ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์—์„œ ํŠธ๋žœ์žญ์…˜์ด ์‹คํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์„œ๋กœ ๋…๋ฆฝ์ ์œผ๋กœ ์ปค๋ฐ‹๋œ๋‹ค. ๋”ฐ๋ผ์„œ ํšŒ์›๊ฐ€์ž…์€ ๋˜์ง€ ์•Š์•˜์ง€๋งŒ ์•Œ๋ฆผ์€ ์ „์†ก๋˜๋Š” ์ข‹์ง€ ๋ชปํ•œ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•œ๋‹ค. 

 

 

2. ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ์ƒํ™ฉ๋“ค

- 1. event๋ฅผ ๋น„๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌ & memberService ์—์„œ ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฒฝ์šฐ

    @Transactional
    public void register(String name) throws Exception {
        // ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ ๋กœ์ง
        memberRepository.save(Member.builder().name(name).build());

        // ์ด๋ฒคํŠธ ๋“ฑ๋ก
        publisher.publishEvent(new RegisteredEvent(name));

        // ์˜ˆ์™ธ ๋ฐœ์ƒ
        throw new RuntimeException("member service ์—๋Ÿฌ");
    }
}

 

memberService์—์„œ ์˜ˆ์™ธ๊ฐ€ ํ„ฐ์กŒ์ง€๋งŒ ๋น„๋™๊ธฐ๋กœ ์‹คํ–‰๋œ ํŠธ๋žœ์žญ์…˜์€ ์ •์ƒ์ ์œผ๋กœ ์ปค๋ฐ‹๋จ

 

 

- 2. event๋ฅผ ๋™๊ธฐ๋กœ ์ฒ˜๋ฆฌ & ์•Œ๋žŒ์„ ๋ณด๋‚ด๋˜ ์ค‘ ์—๋Ÿฌ๊ฐ€ ๋‚œ ๊ฒฝ์šฐ

@Service
@RequiredArgsConstructor
public class MemberService {

    private final ApplicationEventPublisher publisher;
    private final MemberRepository memberRepository;

    @Transactional
    public void register(String name) throws Exception {
        // ํšŒ์›๊ฐ€์ž… ์ฒ˜๋ฆฌ ๋กœ์ง
        memberRepository.save(Member.builder().name(name).build());

        // ์ด๋ฒคํŠธ ๋“ฑ๋ก
        publisher.publishEvent(new RegisteredEvent(name));
    }
}


@Service
@RequiredArgsConstructor
@Transactional
public class AlarmService {
    private final AlarmRepository alarmRepository;
    public void send(String name) throws InterruptedException {
        alarmRepository.save(Alarm.builder().createdAt(LocalDateTime.now()).build());
        System.out.println(name + "์—๊ฒŒ push ์•Œ๋ฆผ ๋ฐœ์†ก");
        // ์˜ˆ์™ธ ๋ฐœ์ƒ
        throw new RuntimeException("member service ์—๋Ÿฌ");
    }
}

 

member ์ €์žฅ์€ ์ •์ƒ์ ์œผ๋กœ ๋˜์—ˆ์ง€๋งŒ ๋ถ€๊ฐ€์ ์ธ ์ž‘์—…์„ ํ•˜๋˜ ์ค‘ ์—๋Ÿฌ๊ฐ€ ๋‚œ ๊ฒƒ์ด๋‹ค. ํ•˜์ง€๋งŒ member ์ €์žฅํ–ˆ๋˜ ๋ถ€๋ถ„๊นŒ์ง€ ๋กค๋ฐฑ๋˜๋ฉด์„œ ์ฟผ๋ฆฌ๊ฐ€ ๋‚˜๊ฐ€์ง€ ์•Š์•˜๋‹ค. 

 

 

์ด๋ฐ–์—๋„ ๋งŽ์€ ๊ฒฝ์šฐ์˜ ์ˆ˜๊ฐ€ ์žˆ์ง€๋งŒ ์ด์ •๋„๊นŒ์ง€๋งŒ ์†Œ๊ฐœํ•˜๊ฒ ๋‹ค. ๊ทธ๋Ÿผ ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์„๊นŒ??

 

 

3. TransactionalEventListener

์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋Š” @TransactionEventListener๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค. @TransactionEventListener๋Š” Event์˜ ์‹ค์งˆ์ ์ธ ๋ฐœ์ƒ์„ ํŠธ๋žœ์žญ์…˜์˜ ์ข…๋ฃŒ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์‚ผ๋Š”๋‹ค.

 

- @TransactionalEventListener ์˜ต์…˜

@TransactionalEventListener์„ ์ด์šฉํ•˜๋ฉด ํŠธ๋žœ์žญ์…˜์˜ ์–ด๋–ค ํƒ€์ด๋ฐ์— ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ง€ ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ต์…˜์€ TransactionPhase์„ ์‚ฌ์šฉํ•˜์—ฌ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๊ณ , ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์˜ต์…˜์ด ์žˆ๋‹ค.

 

  • AFTER_COMMIT (๊ธฐ๋ณธ๊ฐ’) - ํŠธ๋žœ์žญ์…˜์ด ์„ฑ๊ณต์ ์œผ๋กœ ๋งˆ๋ฌด๋ฆฌ(commit)๋ฌ์„ ๋•Œ ์ด๋ฒคํŠธ ์‹คํ–‰
  • AFTER_ROLLBACK – ํŠธ๋žœ์žญ์…˜์ด rollback ๋ฌ์„ ๋•Œ ์ด๋ฒคํŠธ ์‹คํ–‰
  • AFTER_COMPLETION – ํŠธ๋žœ์žญ์…˜์ด ๋งˆ๋ฌด๋ฆฌ ๋์„ ๋•Œ(commit or rollback) ์ด๋ฒคํŠธ ์‹คํ–‰
  • BEFORE_COMMIT - ํŠธ๋žœ์žญ์…˜์˜ ์ปค๋ฐ‹ ์ „์— ์ด๋ฒคํŠธ ์‹คํ–‰

 

- Handler ํด๋ž˜์Šค์— AFTER_COMPLETION ์˜ต์…˜์„ ๋‹ฌ๊ณ 

- ์•Œ๋ฆผ์„ ๋ฐœ์†กํ•˜๋‹ค ์˜ˆ์™ธ๊ฐ€ ํ„ฐ์ง€๋Š” ์ƒํ™ฉ์„ ๊ฐ€์ •ํ•ด๋ณด๊ฒ ๋‹ค.

 

@Component
@RequiredArgsConstructor
public class SmsEventHandler {

    private final AlarmService alarmService;
    private final AlimTalkService alimTalkService;

    //    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void sendFCM(RegisteredEvent event) throws InterruptedException {
        alarmService.send(event.getName());
    }

    //    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void sendAlimTalk(RegisteredEvent event) throws Exception {
        alimTalkService.send(event.getName());
    }
}

 

 

์•„๊นŒ ์œ„์—์„œ ๋ฌธ์ œ๋˜๋Š” ์ƒํ™ฉ์„ ์†Œ๊ฐœํ–ˆ๋Š”๋ฐ, ๊ทธ๋• member๊นŒ์ง€ ์ €์žฅ๋˜์ง€ ์•Š์•˜๋‹ค.

ํ•˜์ง€๋งŒ ์ด๋ฒˆ์—” member๋Š” ์ž˜ ์ €์žฅ๋˜๊ณ  ์˜ˆ์™ธ๊ฐ€ ํ„ฐ์ง€๋Š” ๋ชจ์Šต์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. 

 

 

AFTER_COMPLETION ์ฃผ์˜ ์‚ฌํ•ญ

TransactionalEventListener์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด๋ฒคํŠธ ๊ตฌ์กฐ๋ฅผ ๋„์ž…ํ•˜์—ฌ ๊ฐ„๊ฒฐํ•œ ์ฝ”๋“œ ๊ตฌ์กฐ๋ฅผ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์–ด์„œ ์žฅ์ ์ด ์žˆ์ง€๋งŒ, ํŠธ๋žœ์žญ์…˜๊ณผ ํ•จ๊ป˜ ์ด๋ฒคํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ ์ฃผ์˜์‚ฌํ•ญ์ด ์žˆ๋‹ค. phase ๊ฐ’์ด AFTER_COMMIT ์œผ๋กœ ์ •์˜ํ•ด๋†“์€ ๊ฒฝ์šฐ ๋ฆฌ์Šค๋„ˆ ์ฝ”๋“œ ์•ˆ์—์„œ ๋‹ค์‹œ ํŠธ๋žœ์žญ์…˜์„ ์ฒ˜๋ฆฌํ•˜๋ฉด ํ•ด๋‹น ํŠธ๋žœ์žญ์…˜์€ ์ปค๋ฐ‹๋˜์ง€ ์•Š๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ•œ๋‹ค.

 

@Component
@RequiredArgsConstructor
public class SmsEventHandler {

    private final AlarmService alarmService;
    private final AlimTalkService alimTalkService;

    //    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void sendFCM(RegisteredEvent event) throws InterruptedException {
        alarmService.send(event.getName());
    }

    //    @Async
    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    public void sendAlimTalk(RegisteredEvent event) throws Exception {
        alimTalkService.send(event.getName());
    }
}


@Service
@RequiredArgsConstructor
@Transactional
public class AlarmService {
    private final AlarmRepository alarmRepository;
    
    // ํŠธ๋žœ์žญ์…˜ commit ์•ˆ ๋จ!!!!
    public void send(String name) throws InterruptedException {
        alarmRepository.save(Alarm.builder().createdAt(LocalDateTime.now()).build());
        System.out.println(name + "์—๊ฒŒ push ์•Œ๋ฆผ ๋ฐœ์†ก");
    }
}

 

 

์ด ํ˜„์ƒ์— ๋Œ€ํ•œ ์›์ธ์€ TransactionSynchronization ์˜ afterCommit ์ฃผ์„๋ถ€๋ถ„์— ์„ค๋ช…๋˜์–ด ์žˆ๋‹ค.

/** * Invoked after transaction commit. Can perform further operations right * <i>after</i> the main transaction has <i>successfully</i> committed. * <p>Can e.g. commit further operations that are supposed to follow on a successful * commit of the main transaction, like confirmation messages or emails. * <p><b>NOTE:</b> The transaction will have been committed already, but the * transactional resources might still be active and accessible. As a consequence, * any data access code triggered at this point will still "participate" in the * original transaction, allowing to perform some cleanup (with no commit following * anymore!), unless it explicitly declares that it needs to run in a separate * transaction. Hence: <b>Use {@code PROPAGATION_REQUIRES_NEW} for any * transactional operation that is called from here.</b> * @throws RuntimeException in case of errors; will be <b>propagated to the caller</b> * (note: do not throw TransactionException subclasses here!) **/

 

์š”์•ฝํ•˜์ž๋ฉด, ์ด์ „์˜ ์ด๋ฒคํŠธ๋ฅผ publish ํ•˜๋Š” ์ฝ”๋“œ์—์„œ ํŠธ๋žœ์žญ์…˜์ด ์ด๋ฏธ ์ปค๋ฐ‹ ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— AFTER_COMMIT ์ดํ›„์— ์ƒˆ๋กœ์šด ํŠธ๋žœ์žญ์…˜์„ ์ˆ˜ํ–‰ํ•˜๋ฉด ํ•ด๋‹น ๋ฐ์ดํ„ฐ์†Œ์Šค ์ƒ์—์„œ๋Š” ํŠธ๋žœ์žญ์…˜์„ ์ปค๋ฐ‹ํ•˜์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

 

๋”ฐ๋ผ์„œ @Transactional ์–ด๋…ธํ…Œ์ด์…˜์„ ์ ์šฉํ•œ ์ฝ”๋“œ์—์„œ PROPAGATION_REQUIRES_NEW ์˜ต์…˜์„ ์ง€์ •ํ•˜์ง€ ์•Š๋Š”๋‹ค๋ฉด (๋งค๋ฒˆ ์ƒˆ๋กœ์šด ํŠธ๋žœ์žญ์…˜์„ ์—ด์–ด์„œ ๋กœ์ง์„ ์ฒ˜๋ฆฌํ•˜๋ผ๋Š” ์˜๋ฏธ) ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ์—์„œ ํŠธ๋žœ์žญ์…˜์— ์˜์กดํ•œ ๋กœ์ง์„ ์‹คํ–‰ํ–ˆ์„ ๊ฒฝ์šฐ ์ด ํŠธ๋žœ์žญ์…˜์€ ์ปค๋ฐ‹๋˜์ง€ ์•Š๋Š”๋‹ค.

 

 

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• 1)

์œ„ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์ฒซ ๋ฒˆ์งธ ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” AFTER_COMMIT ์ดํ›„์— ๋™์ผํ•œ ๋ฐ์ดํ„ฐ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค. ๋ฐ”๋กœ @Async ์–ด๋…ธํ…Œ์ด์…˜์„ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

@Async
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
public void sendAlimTalk(RegisteredEvent event) throws Exception {
    alimTalkService.send(event.getName());
}

 

์œ„ ์ฝ”๋“œ๋Š” ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ๋กœ์ง์ด ๋ณ„๋„์˜ ์Šค๋ ˆ๋“œ์—์„œ ์‹คํ–‰๋˜์–ด ํŠธ๋žœ์žญ์…˜์ด ์ปค๋ฐ‹๋˜๊ธฐ ๋•Œ๋ฌธ์— ์˜๋„ํ•œ ๊ฒฐ๊ณผ๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. 

๋˜ํ•œ ๋ฌธ์ œ๊ฐ€ ๋˜๋Š” ์ƒํ™ฉ 1๋ฒˆ์งธ, 2๋ฒˆ์งธ ๋ฌธ์ œ๋„ ์ „๋ถ€ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

 

ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• 2)

๋‘๋ฒˆ์งธ ๋ฐฉ๋ฒ•์œผ๋ก  @TransactionalEventListener ์–ด๋…ธํ…Œ์ด์…˜์— ์ถ”๊ฐ€๋กœ @Transactional(propagation = Propagation.REQUIRES_NEW) ์„ ๋ถ™์—ฌ์ฃผ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ์˜ ๋กœ์ง ์•ˆ์—์„œ ์‹คํ–‰๋˜๋Š” @Transactional ๋กœ์ง์„ ์œ„ํ•œ ์ƒˆ๋กœ์šด ํŠธ๋žœ์žญ์…˜์ด ์ด์ „์˜ ํŠธ๋žœ์žญ์…˜๊ณผ ๊ตฌ๋ถ„๋˜์–ด ์ƒˆ๋กญ๊ฒŒ ์‹œ์ž‘ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ ํŠธ๋žœ์žญ์…˜๊ณผ๋Š” ๋ณ„๋„์˜ ๋ถ„๋ฆฌ๋œ ํŠธ๋žœ์žญ์…˜ ์•ˆ์—์„œ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ ๋กœ์ง์ด ์‹คํ–‰๋œ๋‹ค.

    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void sendAlimTalk(RegisteredEvent event) throws Exception {
        alimTalkService.send(event.getName());
    }