@Inject
  public SqlQueryManager(
      QueryManagerConfig config,
      QueryMonitor queryMonitor,
      QueryIdGenerator queryIdGenerator,
      LocationFactory locationFactory,
      Map<Class<? extends Statement>, QueryExecutionFactory<?>> executionFactories) {
    checkNotNull(config, "config is null");

    this.executionFactories = checkNotNull(executionFactories, "executionFactories is null");

    this.queryExecutor = Executors.newCachedThreadPool(threadsNamed("query-scheduler-%d"));
    this.queryExecutorMBean = new ThreadPoolExecutorMBean((ThreadPoolExecutor) queryExecutor);

    this.queryMonitor = checkNotNull(queryMonitor, "queryMonitor is null");
    this.locationFactory = checkNotNull(locationFactory, "locationFactory is null");
    this.queryIdGenerator = checkNotNull(queryIdGenerator, "queryIdGenerator is null");

    this.maxQueryAge = config.getMaxQueryAge();
    this.maxQueryHistory = config.getMaxQueryHistory();
    this.clientTimeout = config.getClientTimeout();

    queryManagementExecutor =
        Executors.newScheduledThreadPool(
            config.getQueryManagerExecutorPoolSize(), threadsNamed("query-management-%d"));
    queryManagementExecutorMBean =
        new ThreadPoolExecutorMBean((ThreadPoolExecutor) queryManagementExecutor);
    queryManagementExecutor.scheduleAtFixedRate(
        new Runnable() {
          @Override
          public void run() {
            try {
              removeExpiredQueries();
            } catch (Throwable e) {
              log.warn(e, "Error removing old queries");
            }
            try {
              failAbandonedQueries();
            } catch (Throwable e) {
              log.warn(e, "Error removing old queries");
            }
          }
        },
        200,
        200,
        TimeUnit.MILLISECONDS);
  }