Wykonywanie akcji w określonym czasie

0

Designuje uproszczony system typu allegro - user wystawia aukcje, a one po jakimś określonym czasie się kończą. W momencie zakończenia musze wykonać dodatkowe side effecty -> wyznaczyc zwyciezce, zamknąć aukcje oraz przelać pieniądze przegranym. W jaki sposób moge coś takiego efektywnie wykonać w Springu?

Myślalem, żeby

  1. Odpalić timeouta (lub jakas klejke in memory), który wykona się za x czasu w momencie zapisu aukcji (jednak z uwagi na ich długi czas trwania oraz możliwość resetu systemu jest to raczej opcja średnia).
  2. Wykorzystać crona (np co minute), który będzie pobierał wszystkie skończone aukcje oraz wykonywał side effecty (dla userów aukcje po terminie były by niedostępne - np filtrowaniem)
  3. Wykorzystać jakąś zewnętrzną kolejke do ulepszenia rozwiazania 1.
1

Rozwiazanie 2. Ale zamiast crona to javowy Quartz

1

Ja bym zrobił wersję mieszaną, to jest użył joba/crona/quartza do opublikowania eventu o zakończeniu aukcji i w reakcji na ten event robił różne rzeczy - tak, aby rozdzielić domenę ofertową od pozostałych domen.

3

Rozwiązanie 4. Nie wiązać się z czasem jako takim. Niech będzie sobie cron(quartz), który emituje tiki do wszystkich zainteresowanych w systemie. Każda aukcja ma zapisany tik, w którym ma się skończyć i w momencie gdy odbierze ten lub kolejne tiki, to się kończy i rozgłasza ten fakt, że coś z nią trzeba zrobić.

Najprostszą implementacją, pomijając obserwatora z API języka, będzie użycie Google Guava i EventBus. Bardziej złożona, to jakaś kolejka, która potrafi wydajnie obsługiwać topiki.

1

Edit w osobnym poście, by nikomu nie umknęło:

package pl.koziolekweb._4p;

import com.google.common.eventbus.EventBus;
import com.google.common.eventbus.Subscribe;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class Application {
    public static void main(String[] args) throws InterruptedException {

        EventBus eventBus = new EventBus();
        Aukcja aukcja = new Aukcja(0, 5);
        eventBus.register(aukcja);
        ScheduledExecutorService zegar = Executors.newSingleThreadScheduledExecutor();
        PanTikTak panTikTak = new PanTikTak(eventBus);
        zegar.scheduleAtFixedRate(panTikTak, 1L, 1L, TimeUnit.SECONDS);
    }
}

class PanTikTak implements Runnable {

    private final AtomicInteger tik;
    private final EventBus eventBus;

    PanTikTak(EventBus eventBus) {
        this.eventBus = eventBus;
        this.tik = new AtomicInteger(0);
    }

    @Override
    public void run() {
        int t = tik.addAndGet(1);
        System.out.println("Tik: " + t);
        eventBus.post(new TickEvent(t));
    }
}

class TickEvent{
    final int tick;

    TickEvent(int tick) {
        this.tick = tick;
    }
}

class Aukcja{
    private final int initialTick;
    private final int finalTick;

    public Aukcja(int initialTick, int finalTick) {
        this.initialTick = initialTick;
        this.finalTick = finalTick;
        System.out.println("Zaczynam aukcję");
    }

    @Subscribe
    public void ktoraGodzina(TickEvent tickEvent){
        if(tickEvent.tick > finalTick)
            System.out.println("Zakończ aukcję");
        else
            System.out.println("Obstawiaj");
    }
}

Kompletna aplikacja, która implementuje opcję nr 4. Oczywiście bardzo prymitywna, ale widać, o co chodzi.

1 użytkowników online, w tym zalogowanych: 0, gości: 1