001/*- 002 * #%L 003 * HAPI FHIR JPA Server 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.jpa.search; 021 022import ca.uhn.fhir.jpa.api.svc.ISearchUrlJobMaintenanceSvc; 023import ca.uhn.fhir.jpa.model.sched.HapiJob; 024import ca.uhn.fhir.jpa.model.sched.IHasScheduledJobs; 025import ca.uhn.fhir.jpa.model.sched.ISchedulerService; 026import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition; 027import org.apache.commons.lang3.time.DateUtils; 028import org.quartz.JobExecutionContext; 029import org.quartz.JobExecutionException; 030import org.springframework.beans.factory.annotation.Autowired; 031 032import java.util.Date; 033 034/** 035 * The purpose of this service is to define and register a job that will clean up 036 * entries created by an instance of {@link ResourceSearchUrlSvc}. 037 */ 038public class SearchUrlJobMaintenanceSvcImpl implements ISearchUrlJobMaintenanceSvc, IHasScheduledJobs { 039 040 private ResourceSearchUrlSvc myResourceSearchUrlSvc; 041 042 /** 043 * An hour at 3k resources/second is ~10M resources. That's easy to manage with deletes by age. 044 * We can shorten this if we have memory or storage pressure. MUST be longer that longest transaction 045 * possible to work. 046 */ 047 public static final long OUR_CUTOFF_IN_MILLISECONDS = 1 * DateUtils.MILLIS_PER_HOUR; 048 049 public SearchUrlJobMaintenanceSvcImpl(ResourceSearchUrlSvc theResourceSearchUrlSvc) { 050 myResourceSearchUrlSvc = theResourceSearchUrlSvc; 051 } 052 053 @Override 054 public void removeStaleEntries() { 055 final Date cutoffDate = calculateCutoffDate(); 056 myResourceSearchUrlSvc.deleteEntriesOlderThan(cutoffDate); 057 } 058 059 @Override 060 public void scheduleJobs(ISchedulerService theSchedulerService) { 061 ScheduledJobDefinition jobDetail = new ScheduledJobDefinition(); 062 jobDetail.setId(SearchUrlMaintenanceJob.class.getName()); 063 jobDetail.setJobClass(SearchUrlMaintenanceJob.class); 064 theSchedulerService.scheduleClusteredJob(10 * DateUtils.MILLIS_PER_MINUTE, jobDetail); 065 } 066 067 private Date calculateCutoffDate() { 068 return new Date(System.currentTimeMillis() - OUR_CUTOFF_IN_MILLISECONDS); 069 } 070 071 public static class SearchUrlMaintenanceJob implements HapiJob { 072 073 @Autowired 074 private ISearchUrlJobMaintenanceSvc mySearchUrlJobMaintenanceSvc; 075 076 @Override 077 public void execute(JobExecutionContext theJobExecutionContext) throws JobExecutionException { 078 mySearchUrlJobMaintenanceSvc.removeStaleEntries(); 079 } 080 } 081}