Building a Timer-Driven Session Bean in NetBeans

Enterprise Java developers in Sydney and Melbourne often rely on background processing to keep applications humming outside business hours. A session bean with a timer service is one of the cleanest ways to schedule recurring tasks in the Jakarta EE ecosystem, and NetBeans IDE makes building one straightforward. Whether you are running a billing system for a Sydney fintech or processing nightly reports for a Melbourne logistics firm, the pattern is identical.

The Timer Service, part of the EJB specification, lets you schedule a method at a specific time, after a delay, or on a recurring basis without third-party libraries. For Australian teams operating across AEST and AEDT, this is useful when reconciling daily transactions before the ASX opens at 10:00 AM Sydney time.

This walkthrough covers setting up a project, writing a stateless session bean, attaching a timer, and verifying that everything fires correctly. It assumes a recent NetBeans build (12.0 or later) and comfort with Java EE projects.

Understanding session beans and the Timer Service

A session bean is a server-side object that encapsulates business logic inside an EJB container. Three flavours exist: stateless, stateful, and singleton. For timer-driven workloads, a stateless or singleton bean is usually the right pick, because the container pools instances and timer state survives across invocations. Stateful beans tie to a single client and suit scheduled work poorly.

The Timer Service is the EJB subsystem responsible for executing callback methods when you specify. Trigger a timer declaratively with @Schedule, programmatically with the TimerService API, or through a deployment descriptor. A payroll job firing at the same minute each month suits a declarative schedule, while a job whose time depends on user input needs programmatic control.

Preparing your NetBeans workspace

Before writing code, install JDK 11 or 17 and a Java EE-compatible NetBeans distribution from the Apache archives. Pair it with a local application server; GlassFish 7 or Payara 5 are the most common companions for EJB development in Australian consultancies.

When you inherit code or download a sample repository, spin it up without rebuilding from scratch. The generating from source folder guide walks through importing an existing tree, setting the source level, and pointing the IDE at the right server, which is a real time saver when onboarding a codebase written on a MacBook in Brisbane while your workstation runs Linux.

Writing the session bean

Right-click the EJB module and choose New → Session Bean. NetBeans asks for a name, a package, and whether the bean should be stateless or stateful; pick stateless here. The IDE generates a class annotated with @Stateless plus a remote or local interface.

Add @Schedule to the method you want timed. A simple example reads @Schedule(hour = "2", minute = "0", persistent = true), instructing the container to invoke the method at 2:00 AM every day, a sensible window for Australian batch processing when most users sleep and the AEMO wholesale market is in its lowest-demand phase. To compare bean types, the stateful session bean call reference explains how stateful beans receive data from clients.

Configuring the timer logic

Sometimes the schedule needs more flexibility. Use the TimerService injected into your bean to create timers programmatically, handy when the interval is driven by user actions such as a reminder email five minutes after a customer books a service. Cancel or replace timers at runtime without redeploying.

For complex schedules, learn the cron-like syntax @Schedule accepts, with fields for second, minute, hour, dayOfMonth, month, dayOfWeek, and year. NetBeans offers autocomplete when you hover over the annotation. Server-side timers follow the JVM time zone, so if your team spans Perth and Sydney, set the timezone attribute explicitly.

Running and testing the bean

Hit Run and NetBeans deploys the EJB module to the selected server. Open the server log for lines confirming timer creation. To prove the timer fires, add a System.out.println inside the scheduled method and watch the log each time it triggers, or attach the debugger and set a breakpoint.

Performance tuning often catches teams by surprise. When the scheduled method eats more CPU than expected, point NetBeans at the running JVM and capture a profile. The profiling CPU usage tutorial explains how to attach the profiler and read the flame graph, invaluable when an Australian retailer processes thousands of overnight orders and the batch run starts bleeding into business hours.

Avoiding common pitfalls

Timers and transactions have a complicated relationship. By default, the scheduled method runs without an active transaction, so database writes must declare their own context with @TransactionAttribute. Skip this and writes silently roll back, leaving you wondering why nothing landed in MySQL.

Persistent timers survive a server restart while non-persistent ones vanish when the JVM dies. Choose persistent = true for anything important and rely on non-persistent timers only for short-lived reminders. Avoid storing state in a stateless session bean; each invocation may run on a different pooled instance, so any field you set is effectively random.

Deploying to a production server

When ready to ship, package the bean as part of an EAR and deploy to a managed GlassFish or Payara cluster. Australian hosting providers such as Servers Australia, Vultr's Sydney region, or local AWS and Azure footprints offer reasonable latency for most workloads. Synchronise your server clock via NTP and verify the JVM time zone matches your scheduling assumptions.

Once running, monitor timer executions through JMX or your APM tool of choice, and set up alerts for missed runs, since a timer that silently stops firing is a common source of late-night pages.

Practical recommendations

  • Use stateless beans for short recurring tasks that hold no conversational state.
  • Prefer @Schedule over programmatic timers when the interval is fixed at deploy time.
  • Always set the timezone attribute explicitly if your team spans regions.
  • Declare @TransactionAttribute.REQUIRED on scheduled methods that write to a database.
  • Run a profiler session before pushing to production to catch hot methods early.