Bagaimana cara menjalankan tugas latar belakang dalam aplikasi web berbasis servlet?

97

Saya menggunakan Java dan saya ingin membuat servlet terus berjalan di aplikasi saya, tetapi saya tidak mengerti cara melakukannya. Servlet saya memiliki metode yang memberikan jumlah pengguna dari database setiap hari serta jumlah total pengguna dari seluruh database. Jadi saya ingin terus menjalankan servlet untuk itu.

pritsag
sumber
Apa maksud Anda "terus berjalan"?
Skaffman
1
Apa yang Anda maksud dengan terus berlari? Ini akan berjalan selama server aplikasi Anda berjalan
fmucar
2
Saya tidak mengerti mengapa harus berjalan terus menerus ... jika seseorang menginginkan 'jumlah pengguna' maka mereka memanggil metode servlet Anda dan Anda memberikannya kepada mereka?
trojanfoe
@trojanfoe Sebenarnya saya ingin usercount setiap hari, jadi untuk itu saya harus menjalankan servlet secara manual setiap hari jadi daripada melakukan itu saya ingin menjalankan servlet secara kontinu. jadi saya tidak perlu menjalankan servlet setiap hari.
pritsag
1
@pritsag: Servlet ada untuk melayani permintaan pengguna, bukan untuk menjalankan pekerjaan batch.
Skaffman

Jawaban:

217

Masalah Anda adalah bahwa Anda salah memahami tujuan servlet . Itu dimaksudkan untuk bertindak atas permintaan HTTP, tidak lebih. Anda hanya menginginkan tugas latar belakang yang dijalankan sekali setiap hari.

EJB tersedia? Menggunakan@Schedule

Jika lingkungan Anda kebetulan mendukung EJB (yaitu server Java EE nyata seperti WildFly, JBoss, TomEE, Payara, GlassFish, dll), gunakan @Schedulesaja. Berikut beberapa contohnya:

@Singleton
public class BackgroundJobManager {

    @Schedule(hour="0", minute="0", second="0", persistent=false)
    public void someDailyJob() {
        // Do your job here which should run every start of day.
    }

    @Schedule(hour="*/1", minute="0", second="0", persistent=false)
    public void someHourlyJob() {
        // Do your job here which should run every hour of day.
    }

    @Schedule(hour="*", minute="*/15", second="0", persistent=false)
    public void someQuarterlyJob() {
        // Do your job here which should run every 15 minute of hour.
    }

    @Schedule(hour="*", minute="*", second="*/5", persistent=false)
    public void someFiveSecondelyJob() {
        // Do your job here which should run every 5 seconds.
    }

} 

Ya, itu saja. Penampung akan secara otomatis mengambil dan mengelolanya.

EJB tidak tersedia? MenggunakanScheduledExecutorService

Jika lingkungan Anda tidak mendukung EJB (yaitu Anda tidak menggunakan server Java EE yang sebenarnya, tetapi penampung server barebone seperti Tomcat, Jetty, dll), maka gunakan ScheduledExecutorService. Ini dapat dimulai dengan a ServletContextListener. Inilah contoh awal:

@WebListener
public class BackgroundJobManager implements ServletContextListener {

    private ScheduledExecutorService scheduler;

    @Override
    public void contextInitialized(ServletContextEvent event) {
        scheduler = Executors.newSingleThreadScheduledExecutor();
        scheduler.scheduleAtFixedRate(new SomeDailyJob(), 0, 1, TimeUnit.DAYS);
        scheduler.scheduleAtFixedRate(new SomeHourlyJob(), 0, 1, TimeUnit.HOURS);
        scheduler.scheduleAtFixedRate(new SomeQuarterlyJob(), 0, 15, TimeUnit.MINUTES);
        scheduler.scheduleAtFixedRate(new SomeFiveSecondelyJob(), 0, 5, TimeUnit.SECONDS);
    }

    @Override
    public void contextDestroyed(ServletContextEvent event) {
        scheduler.shutdownNow();
    }

}

Dimana kelas pekerjaan terlihat seperti ini:

public class SomeDailyJob implements Runnable {

    @Override
    public void run() {
        // Do your daily job here.
    }

}
public class SomeHourlyJob implements Runnable {

    @Override
    public void run() {
        // Do your hourly job here.
    }

}
public class SomeQuarterlyJob implements Runnable {

    @Override
    public void run() {
        // Do your quarterly job here.
    }

}
public class SomeFiveSecondelyJob implements Runnable {

    @Override
    public void run() {
        // Do your quarterly job here.
    }

}

Jangan pernah berpikir untuk menggunakan java.util.Timer/ java.lang.Threaddalam lingkungan berbasis Java EE / Servlet

Last but not least, jangan pernah langsung menggunakan java.util.Timerdan / atau java.lang.Threaddi Java EE. Ini resep untuk masalah. Penjelasan terperinci dapat ditemukan dalam jawaban terkait JSF ini pada pertanyaan yang sama: Memijahkan utas dalam kacang yang dikelola JSF untuk tugas terjadwal menggunakan pengatur waktu .

BalusC
sumber
9
@BalucS Terima kasih pak, solusi Anda membantu saya dan saya belajar tentang ScheduledExecutorService yang baru bagi saya karena saya baru mengenal java. Terima kasih sekali lagi.
pritsag
@BalusC: Di mana kelas UpdateCounts harus diletakkan di web.xml?
Ashwin
1
@Ashwin web.xml adalah Deployment Descriptor . Kelas UpdateCount tidak terkait dengan penerapan, jadi tidak harus diletakkan di web.xml
informatik01
12
Satu masalah krusial dengan ScheduledExecutorService: Pastikan untuk menangkap semua pengecualian di pelaksana Anda. Jika pengecualian lolos dari runmetode Anda , pelaksana akan berhenti mengeksekusi secara diam-diam. Ini adalah fitur bukan bug. Baca dokumen dan pelajari dengan beberapa googling.
Basil Bourque
1
@Agi: itu akan terjadi jika scheduler.shutdownNow()tidak dipanggil dengan benar sesuai contoh. Jika ini tidak dipanggil, utas jadwal memang akan terus berjalan.
BalusC
4

Saya akan menyarankan menggunakan perpustakaan seperti kuarsa untuk menjalankan tugas secara berkala. Apa yang sebenarnya dilakukan servlet? Ini mengirimi Anda laporan?

Twister
sumber
ya, ini memberi saya jumlah pengguna yang dibuat per hari dan juga jumlah total pengguna di database saya.
pritsag
1
huuu? Dapatkah Anda menjelaskan arsitektur LENGKAP sistem Anda. Saya tersesat.
Twister
@Twister im baru ke java dan dalam fase belajar Pak dan benar-benar tidak tahu banyak tentang servlet.
pritsag
Masalahnya bukan tentang servlet. Aplikasi apa yang Anda bicarakan? (ps: itu adalah ide yang buruk untuk menghapus komentar Anda, terutama komentar yang saya jawab)
Twister
@twister ketika pengguna akan membuka aplikasi, dia akan mendapatkan semua detail seperti berapa banyak pengguna yang dibuat hari ini, berapa banyak pengguna yang digila sampai sekarang, dll. Dan saya ingin menjalankan servlet yang berjalan di latar belakang secara kontinu sehingga pengguna bisa mendapatkan pembaruan . Saya tahu ini bukan penjelasan yang tepat. (Ps: saya tahu itu ide yang buruk. Maaf untuk itu.)
pritsag
3

Menerapkan dua kelas dan memanggil startTask()di main.

public void startTask()
{
    // Create a Runnable
    Runnable task = new Runnable() {
        public void run() {
            while (true) {
                runTask();
            }
        }
    };

    // Run the task in a background thread
    Thread backgroundThread = new Thread(task);
    // Terminate the running thread if the application exits
    backgroundThread.setDaemon(true);
    // Start the thread
    backgroundThread.start();
}

public void runTask()
{
    try {
        // do something...         
        Thread.sleep(1000);

    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
Ali Alimohammadi
sumber
3
Ini jelas BUKAN cara melakukannya dalam aplikasi web - lihat jawaban di atas oleh @BalusC sebagai gantinya - dia benar di sini dan saya akan mengatakan Anda dapat mempercayai semua jawabannya.
Yoshiya
0

Dalam sistem produksi yang mungkin menjalankan beberapa kontainer non-jee. Gunakan penjadwal perusahaan lain seperti penjadwal Quartz yang dapat dikonfigurasi untuk menggunakan database untuk tugas maamgememt.

Jeryl Cook
sumber