Scheduler doesn't run servlet | Community
Skip to main content
Level 4
April 28, 2025
Solved

Scheduler doesn't run servlet

  • April 28, 2025
  • 5 replies
  • 748 views

Hi, I have a servlet that performs a function, I have tested it and it works, to make it execute it is necessary to write the domain name followed by bin/serviceexecution.

But now we want it to run only every so often, for that we have created a scheduler.

The problem is that the scheduler is executed but when arriving to the call of the servlet, this fails, mentioning that we do not have permissions to execute the servlet.

I think it is because to execute this servlet I need permissions, which I don't know how to set them.

How could I add them or know what is the error.

this is the code I made


@Component(service = Runnable.class, immediate = true)
@Designate(ocd = SchedulerUseConfig.class)
public class SchedulerUse implements Runnable {

    private static final Logger log = LoggerFactory.getLogger(SchedulerUse.class);

    @Reference
    private Scheduler scheduler;

    private int schedulerId;
    private SchedulerUseConfig config;

    @Activate
    @Modified
    protected void activate(SchedulerUseConfig config) {
        this.config = config;
        schedulerId = config.schedulerName().hashCode();
       
        log.info("SchedulerUse: Activating or Modifying");
        updateScheduler();
    }

    @Deactivate
    protected void deactivate() {
        log.info("SchedulerUse: Deactivating");
        removeScheduler();
    }

    private void removeScheduler() {
        log.info("SchedulerUse: Removing Scheduler Job '{}'", schedulerId);
        scheduler.unschedule(String.valueOf(schedulerId));
    }

    private void updateScheduler() {
        removeScheduler();
        if (config.enabled()) {
            log.info("SchedulerUse: Adding scheduler");
            ScheduleOptions scheduleOptions = scheduler.EXPR(config.cronExpression());
            scheduleOptions.name(String.valueOf(schedulerId));
            scheduleOptions.canRunConcurrently(false);
            scheduler.schedule(this, scheduleOptions);
            log.info("SchedulerUse: Cache Clean Scheduler added successfully with cron expression: {}", config.cronExpression());
        } else {
            log.info("SchedulerUse: Scheduler is disabled, no scheduler job created");
        }
    }

    @Override
    public void run() {
        log.info("SchedulerUse: Starting scheduled run");
        if (config.enabled()) {
            try {
                String url = config.baseUrl() + "/bin/serviceexecution";
                URL servletUrl = new URL(url);
                HttpURLConnection connection = (HttpURLConnection) servletUrl.openConnection();
                connection.setRequestMethod("GET");
                int responseCode = connection.getResponseCode();
                log.info("SchedulerUse: Response Code: {}", responseCode);
                if (responseCode != HttpURLConnection.HTTP_OK) {
                    log.error("SchedulerUse: Servlet call failed with response code: {}", responseCode);
                }
            } catch (IOException e) {
                log.error("Error: Error while calling servlet", e);
            }
        } else {
            log.info("Message: Scheduler is disabled, skipping run");
        }
        log.info("Message: Finished scheduled run");
    }
}
Best answer by ShivamKumar

Hi @aaron_dempwolff ,

 

If you want to schedule the logic currently written inside your servlet, the better approach is to define an OSGi service that contains the actual business logic. Then, both your servlet and your scheduler can simply call this service directly instead of making an HTTP call.

 

The issue you're facing is happening because, when your scheduler makes an HTTP request to the servlet, it is treated as an anonymous user (no authentication), and therefore you don't have the permissions to execute the servlet.

Let me know if it works.

Thanks.

5 replies

ShivamKumarAccepted solution
Level 4
April 28, 2025

Hi @aaron_dempwolff ,

 

If you want to schedule the logic currently written inside your servlet, the better approach is to define an OSGi service that contains the actual business logic. Then, both your servlet and your scheduler can simply call this service directly instead of making an HTTP call.

 

The issue you're facing is happening because, when your scheduler makes an HTTP request to the servlet, it is treated as an anonymous user (no authentication), and therefore you don't have the permissions to execute the servlet.

Let me know if it works.

Thanks.

Level 4
May 7, 2025

It works, thank you, even the cool part is that it work now like an scheduler and it works executing manually too.

SantoshSai
Community Advisor
Community Advisor
April 28, 2025

Hi @aaron_dempwolff,

The exact problem in your approach is that the scheduler was making an HTTP call to the servlet endpoint (/bin/serviceexecution) internally.
Since the HTTP call originates from inside AEM without any authentication, it is treated as an anonymous user request.
Because of that, permissions are missing, and the servlet execution fails.

Instead of making an HTTP call from within the scheduler (which treats the request as anonymous and causes permission issues), IMO, the correct architectural approach is:

  • Extract the core business logic from the servlet into a separate OSGi service.

  • Inject and use this service both inside the servlet and the scheduler.

  • This way, the logic runs internally within the OSGi container, bypassing the need for HTTP requests and avoiding authentication or permission issues entirely.

  • It also improves maintainability, testability, and performance since no network overhead is involved.

This way it helps you to ensures that servlets handle HTTP communication only, while business logic is managed independently.

Hope that helps!

Santosh Sai
aanchal-sikka
Community Advisor
Community Advisor
April 29, 2025

@aaron_dempwolff 

 

I second suggestions from @santoshsai  and @shivamkumar 

However, if for some reason you cannot change the code immediately, then consider using SlingRequestProcessor . Please refer the blog:

 

https://kiransg.com/2023/05/16/sling-servlet-helpers/

Aanchal Sikka
AmitVishwakarma
Community Advisor
Community Advisor
April 30, 2025

Hi @aaron_dempwolff ,

You're running into a common AEM mistake: your scheduler is calling your servlet via HTTP, which executes as an anonymous user — causing permission errors when accessing restricted content or services.
Step 1: Extract Business Logic to a Service

@Component(service = MyService.class) public class MyService { private static final Logger log = LoggerFactory.getLogger(MyService.class); public void executeLogic() { // ✅ Put your servlet's logic here log.info("MyService: Logic executed"); } }

Step 2: Use This Service in Your Servlet

@Component( service = Servlet.class, property = { "sling.servlet.paths=/bin/serviceexecution", "sling.servlet.methods=GET" } ) public class MyServlet extends SlingSafeMethodsServlet { @Reference private MyService myService; @Override protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws IOException { myService.executeLogic(); // ✅ Call the shared logic response.getWriter().write("Logic executed from servlet"); } }

Step 3: Use Same Service in Your Scheduler Update your scheduler:

@Component(service = Runnable.class, immediate = true) @Designate(ocd = SchedulerUseConfig.class) public class SchedulerUse implements Runnable { private static final Logger log = LoggerFactory.getLogger(SchedulerUse.class); @Reference private Scheduler scheduler; @Reference private MyService myService; // ✅ Inject business logic private int schedulerId; private SchedulerUseConfig config; @Activate @Modified protected void activate(SchedulerUseConfig config) { this.config = config; schedulerId = config.schedulerName().hashCode(); updateScheduler(); } @Deactivate protected void deactivate() { removeScheduler(); } private void removeScheduler() { scheduler.unschedule(String.valueOf(schedulerId)); } private void updateScheduler() { removeScheduler(); if (config.enabled()) { ScheduleOptions scheduleOptions = scheduler.EXPR(config.cronExpression()); scheduleOptions.name(String.valueOf(schedulerId)); scheduleOptions.canRunConcurrently(false); scheduler.schedule(this, scheduleOptions); } } @Override public void run() { log.info("Scheduler: Triggering logic execution"); myService.executeLogic(); // ✅ Call shared logic (no HTTP) } }

Benefits of This Approach:
- No authentication issues
- No unnecessary HTTP overhead
- Centralized logic
- Cleaner separation of concerns
- Works in Cloud Service, AMS, On-Prem setups

Regards,
Amit

aanchal-sikka
Community Advisor
Community Advisor
May 5, 2025

@aaron_dempwolff Did you find the suggestions helpful? Please let us know if you require more information. Otherwise, please mark the answer as correct for posterity. If you've discovered a solution yourself, we would appreciate it if you could share it with the community. Thank you!

Aanchal Sikka