5

This is a philosophical question (maybe not properly) ... I'm wondering about being able to have informations about the scope size for every batch chunk. OK, it's possibible to get the scope size() within an execute call of the batch, but what if I'd like to have informations about this size at Batch class constructor level? So, when someone call

ID batchprocessid = Database.executeBatch(new myBatch(), x);

could I know, in the batch constructor, the value of x?




RECAP

1 - JEREMY NOTTINGHAM SOLUTION:

You can set up your constructor to take the batch size as an argument, and then have access to it later, as long as you implement Database.Stateful:

    global class myBatch implements Database.Batchable<sObject>, Database.Stateful
{
    private Integer batchSize;
    global myBatch(Integer batchSize)
    {
        this.batchSize = batchSize;
        system.debug('batch size: ' + this.batchSize);

        //other constructor stuff
    }
    ...
}

Then your call to run the batch looks like this:

ID batchprocessid = Database.executeBatch(new myBatch(x), x);

1 - MY ANSWER:

I just considered your solution, but my question was a bit harder, i.e. : your solutions works until I know I have to call the myBatch class constructor passing x as parameter, but this way someone else could always call the empty constructor, and I would not be able to catch the scope size.

I would like to be able to do it in any situation , even if someone else call my Batch class constructor (any constructor he wants to call)!

5
  • seems like if this was a requirement your just won't have an empty constructor on the class.
    – NSjonas
    Commented May 29, 2015 at 7:27
  • mmh, cannot catch the meaning of your thought..
    – user9959
    Commented May 29, 2015 at 8:48
  • 1
    If you have an explicit constructor and don't define an empty one, no one will be able to call the empty constructor because it will no longer exist.
    – Adrian Larson
    Commented May 29, 2015 at 18:16
  • sure...btw I don't want to have any explicit constructor ( in that case , ok , we should have declared the empty one), i don't need that solution, i wonder about having the required information by using no constructors.
    – user9959
    Commented May 29, 2015 at 18:19
  • 1
    I think your asking a bit too much out of the programming language. Without a defined constructor, there would be no way to access the data your interested in anyways. But a good design would make this requirement easy enough to accomplish (I like @MarkSmiths approach of protecting the class and delegating access through a service class).
    – NSjonas
    Commented May 29, 2015 at 18:40

5 Answers 5

4
+50

I don't believe that you can.

Instead, consider protecting access to your batcheable class and provide a service class that calls the constructor for you, passing in the batch size, and then you call

global static class myService {
    global static void RunMyBatch(Integer batchSize) {
        myBatch theBatch = new myBatch (batchSize); // Batch size in constructor
        Database.executeBatch(theBatch, batchSize);
    }
}
2
  • I already considered this option. The mine was simply"philosophical" question :)
    – user9959
    Commented May 22, 2015 at 15:50
  • Also, I think this could be accomplished using the Jeremy solution, that does not solve my problem, but is a bit simplier than yours!
    – user9959
    Commented May 28, 2015 at 16:05
2

There are good reasons why the question isn't just philosophical.

I have a batch which must run with scope 100 (any less would affect performance, any more could hit limits and fail). There are a number of ways I can make this scope size available (public final Integer BATCH_SIZE, or a Custom Setting), but there is no way to semantically guarantee it gets used. Like you said, some other developer might try to use my batch without realizing the limit, since there's nothing at compile or run-time (other than the batch executions failing) that tell them it's wrong.

How about this: make the constructor private and force developers to execute the batch via a public static method.

public class MyBatch implements Database.Batchable<Id> {

    public static void executeInstance(Integer batchSize) {
        Database.executeBatch(new MyBatch(), batchSize);
    }

    private MyBatch(){}

    public List<Id> start(Database.BatchableContext bc) {
        ...
    }

    public void execute(Database.BatchableContext bc, List<Id> accIds) {
        ...
    }

    public void finish(Database.BatchableContext bc) {
        ...
    }

}

The private constructor guarantees it cannot be constructed outside of the class, i.e. Database.executeBatch(new MyBatch(), X). The only option available to developers is MyBatch.executeInstance(X), where you can access the value of X (and, in my case, validate it).

1

Yes, it's possible.

When you call your batch class :

ID batchprocessid = Database.executeBatch(new MyBatch(), x);

You can get the TotalJobItems attribute of the AsyncApexJob object like this :

public class MyBatch implements Database.Batchable<SObject>, Database.AllowsCallouts {

    public database.querylocator start(Database.BatchableContext bc) {
        Id jobId = bc.getJobId();

        List<AsyncApexJob> aaj = [SELECT Id, TotalJobItems FROM AsyncApexJob WHERE Id=:jobId];

        Integer totalJobs = 0;

        if(aaj.size() > 0) {
            totalJobs = aaj[0].TotalJobItems; // The number x you want
        } 
    }
}
2
  • I'd like to know the number of record processed by any scope, not the number of total chunks. And I'd like to have this information in the constructor of the batch, not wothin the start method.
    – user9959
    Commented May 22, 2015 at 13:33
  • Ha ! In the constructor, I'm not sure you can get this information !
    – SF_user
    Commented May 22, 2015 at 13:35
1

You can set up your constructor to take the batch size as an argument, and then have access to it later, as long as you implement Database.Stateful:

global class myBatch implements Database.Batchable<sObject>, Database.Stateful
{
    private Integer batchSize;
    global myBatch(Integer batchSize)
    {
        this.batchSize = batchSize;
        system.debug('batch size: ' + this.batchSize);

        //other constructor stuff
    }
    ...
}

Then your call to run the batch looks like this:

ID batchprocessid = Database.executeBatch(new myBatch(x), x);
1
  • Hi Jeremy, thanks for your effort. I just considered your solution, but my question was a bit harder, i.e. : your solutions works until I know I have to call the myBatch class constructor passing x as parameter, but this way someone else could always call the empty constructor, and I would not be able to catch the scope size. I would like to be able to do it in any situation , even if someone else call my Batch class constructor (any constructor he wants to call). Whatever, many thanks!
    – user9959
    Commented May 28, 2015 at 15:56
0

It is not possible to get this data in constructor I believe. Can you please share, what are you trying to do with this number of records processed by scope. We might be able to suggest some work around.

You must log in to answer this question.