If the batch query is same, then it makes sense to abort the currently running batch and execute a new one which will also pick up records of last batch.
Also, if the batch is in Holding or Queued state that means the Start method was not called and thus when start method will be called, it will also pick up new records, meaning we don't need to run a new batch.
public static void addBatchIfNotRunning(Id apexBatchClassId){
ApexAsyncJob asyncJobList = [Select Id From ApexAsyncJob where ApexClassId=:apexBatchClassId AND JobType='BatchApex' and Status In ('Processing','Preparing','Holding','Queued')];
boolean isNeedToInitiateNewBatch = true;
if(!asyncJobList.isEmpty()){
for(ApexAsyncJob as : asyncJobList){
if(as.Status == 'Processing' || as.Status == 'Preparing'){ //As start method of batch is running or run, it wont pick new records so abort it
System.abortJob(as.Id);
}else{
//Batch is already queued or in Holding stage so it will pick up new records
isNeedToInitiateNewBatch = false;
}
}
}
if(isNeedToInitiateNewBatch){
//Initiate Batch
}
}