package com.trendrr.beanstalk; import java.util.Date; import java.util.HashSet; import java.util.Set; import java.util.logging.Logger; public class BeanstalkPool { protected Logger log = Logger.getLogger("com.trendrr.beanstalk"); Set<BeanstalkClient> clients = new HashSet<>(); int maxClients = 30; long maxUseTime = 20 * 60 * 1000; //max checkout time is 20 minutes. long maxIdleTime = 20 * 60 * 1000; //connection will be removed after no use. private String addr; private int port; private String tube = null; /** * setup a new pool. * * @param addr address of the beanstalkd server to connection to * @param port port of the beanstalkd server * @param maxPoolSize maximum number of clients allowed in the pool (0 for infinity) * @param tube All operations for the client will work on the tube. */ public BeanstalkPool(String addr, int port, int maxPoolSize, String tube) { this.addr = addr; this.port = port; this.maxClients = maxPoolSize; this.tube = tube; } /** * setup a new pool. * * @param addr address of the beanstalkd server to connection to * @param port port of the beanstalkd server * @param maxPoolSize maximum number of clients allowed in the pool (0 for infinity) */ public BeanstalkPool(String addr, int port, int maxPoolSize) { this(addr, port, maxPoolSize, null); } /** * returns a client to the pool * * @param client */ public synchronized void done(BeanstalkClient client) { client.inUseSince = null; } /** * This gets a client from the pool. will throw a BeanstalkException if * there are more then the maximum number of clients checked out. * * @return */ public synchronized BeanstalkClient getClient() throws BeanstalkException { /* * synchronized, but should be fast as the client initialization code happens lazily. */ Set<BeanstalkClient> toRemove = new HashSet<>(); Date max = new Date(new Date().getTime() - this.maxUseTime); Date maxIdle = new Date(new Date().getTime() - this.maxIdleTime); BeanstalkClient returnClient = null; try { /* * Here we iterate over all the clients and reap any that need reaping. * TODO: we could restrict this to only loop over once every minute or so. * for now I don't see it being a huge problem. */ for (BeanstalkClient client : clients) { if (client.inUseSince != null && client.inUseSince.before(max)) client.reap = true; if (client.lastUsed != null && client.lastUsed.before(maxIdle)) client.reap = true; if (client.con != null && !client.con.isOpen()) client.reap = true; if (client.reap) toRemove.add(client); else if (returnClient == null && client.inUseSince == null) { client.inUseSince = new Date(); client.lastUsed = new Date(); returnClient = client; } } } finally { for (BeanstalkClient c : toRemove) { log.finer("REAPING Client: " + c); c.pool = null; this.clients.remove(c); c.close(); } } if (returnClient != null) return returnClient; if (this.maxClients > 0 && this.clients.size() >= this.maxClients) { log.severe("Too many clients in use!"); throw new BeanstalkException("To many clients in use"); } BeanstalkClient client = new BeanstalkClient(this.addr, this.port, this.tube, this); this.clients.add(client); client.inUseSince = new Date(); return client; } /** * returns the number of active clients in the pool * * @return */ public int getPoolSize() { return this.clients.size(); } }