Skip to content

Add poolMaxIdleTime configuration option to TCP appenders #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,9 @@ Find more advanced examples in the [examples directory](examples).
* **poolSize**: Number of concurrent tcp connections (minimum 1). Default: 2.
* **poolMaxWaitTime**: Maximum amount of time (in milliseconds) to wait for a connection to become
available from the pool. A value of -1 disables the timeout. Default: 5,000 milliseconds.

* **poolMaxIdleTime**: Maximum amount of time (in seconds) that a pooled connection can be idle
before it is considered 'stale' and will not be reused. A value of -1 disables the max idle time
feature. Default: -1 (disabled).

`de.siegmar.logbackgelf.GelfTcpTlsAppender`

Expand Down
1 change: 1 addition & 0 deletions examples/advanced_tcp.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<retryDelay>3000</retryDelay>
<poolSize>2</poolSize>
<poolMaxWaitTime>5000</poolMaxWaitTime>
<poolMaxIdleTime>10</poolMaxIdleTime>
<encoder class="de.siegmar.logbackgelf.GelfEncoder">
<originHost>localhost</originHost>
<includeRawMessage>false</includeRawMessage>
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/de/siegmar/logbackgelf/GelfTcpAppender.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public class GelfTcpAppender extends AbstractGelfAppender {
private static final int DEFAULT_RETRY_DELAY = 3_000;
private static final int DEFAULT_POOL_SIZE = 2;
private static final int DEFAULT_POOL_MAX_WAIT_TIME = 5_000;
private static final int DEFAULT_POOL_MAX_IDLE_TIME = -1;

/**
* Maximum time (in milliseconds) to wait for establishing a connection. A value of 0 disables
Expand Down Expand Up @@ -66,6 +67,13 @@ public class GelfTcpAppender extends AbstractGelfAppender {
*/
private int poolMaxWaitTime = DEFAULT_POOL_MAX_WAIT_TIME;

/**
* Maximum amount of time (in seconds) that a pooled connection can be idle before it is
* considered 'stale' and will not be reused. A value of -1 disables the max idle time feature.
* Default: -1 (disabled).
*/
private int poolMaxIdleTime = DEFAULT_POOL_MAX_IDLE_TIME;

private SimpleObjectPool<TcpConnection> connectionPool;

public int getConnectTimeout() {
Expand Down Expand Up @@ -121,7 +129,7 @@ protected void startAppender() {

connectionPool = new SimpleObjectPool<>(() -> new TcpConnection(initSocketFactory(),
addressResolver, getGraylogPort(), connectTimeout),
poolSize, poolMaxWaitTime, reconnectInterval);
poolSize, poolMaxWaitTime, reconnectInterval, poolMaxIdleTime);
}

protected SocketFactory initSocketFactory() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,20 @@
public abstract class AbstractPooledObject {

private final long createdAt = System.currentTimeMillis();
private long lastBorrowed = createdAt;

final long lifeTime() {
return System.currentTimeMillis() - createdAt;
}

final long lastBorrowed() {
return lastBorrowed;
}

final void borrow() {
this.lastBorrowed = System.currentTimeMillis();
}

protected void close() {
}

Expand Down
16 changes: 13 additions & 3 deletions src/main/java/de/siegmar/logbackgelf/pool/SimpleObjectPool.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ public class SimpleObjectPool<T extends AbstractPooledObject> {
private final PooledObjectFactory<T> objectFactory;
private final int maxWaitTime;
private final int maxLifeTime;
private final int maxIdleTime;

public SimpleObjectPool(final PooledObjectFactory<T> objectFactory,
final int poolSize, final int maxWaitTime,
final int maxLifeTime) {
final int maxLifeTime, final int maxIdleTime) {

if (poolSize < 1) {
throw new IllegalArgumentException("poolSize must be > 0");
Expand All @@ -47,6 +48,7 @@ public SimpleObjectPool(final PooledObjectFactory<T> objectFactory,
this.objectFactory = objectFactory;
this.maxWaitTime = maxWaitTime;
this.maxLifeTime = maxLifeTime < 0 ? maxLifeTime : maxLifeTime * MILLIS_PER_SECOND;
this.maxIdleTime = maxIdleTime < 0 ? maxIdleTime : maxIdleTime * MILLIS_PER_SECOND;

for (int i = 0; i < poolSize; i++) {
final T pooledObject = this.objectFactory.newInstance();
Expand Down Expand Up @@ -87,11 +89,19 @@ public T borrowObject() throws InterruptedException {
}
}

return needToEvict(pooledObject) ? recycle(pooledObject) : pooledObject;
final T result = needToEvict(pooledObject) ? recycle(pooledObject) : pooledObject;
result.borrow();
return result;
}

private boolean needToEvict(final T pooledObject) {
return maxLifeTime < 0 || pooledObject.lifeTime() > maxLifeTime;
if (maxLifeTime > 0 && pooledObject.lifeTime() > maxLifeTime) {
return true;
} else if (maxIdleTime >= 0 && (System.currentTimeMillis() - pooledObject.lastBorrowed()) > maxIdleTime) {
return true;
} else {
return false;
}
}

private T recycle(final T oldInstance) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public MyPooledObject newInstance() {
@Test
public void simple() throws InterruptedException {
final SimpleObjectPool<MyPooledObject> pool =
new SimpleObjectPool<>(factory, 2, 100, 100);
new SimpleObjectPool<>(factory, 2, 100, 100, 100);

for (int i = 0; i < 10; i++) {
final MyPooledObject o1 = pool.borrowObject();
Expand All @@ -56,7 +56,7 @@ public void simple() throws InterruptedException {
@Test
public void invalidate() throws InterruptedException {
final SimpleObjectPool<MyPooledObject> pool =
new SimpleObjectPool<>(factory, 2, 100, 100);
new SimpleObjectPool<>(factory, 2, 100, 100, 100);

final MyPooledObject o1 = pool.borrowObject();
assertEquals(1, o1.getId());
Expand All @@ -71,6 +71,28 @@ public void invalidate() throws InterruptedException {
pool.returnObject(o3);
}

@Test
public void maxLastBorrowed() throws InterruptedException {
final SimpleObjectPool<MyPooledObject> pool =
new SimpleObjectPool<>(factory, 1, 100, 100, 0);

final MyPooledObject o1 = pool.borrowObject();
assertEquals(1, o1.getId());
pool.returnObject(o1);

Thread.sleep(2);

final MyPooledObject o2 = pool.borrowObject();
assertEquals(2, o2.getId());
pool.returnObject(o2);

Thread.sleep(2);

final MyPooledObject o3 = pool.borrowObject();
assertEquals(3, o3.getId());
pool.returnObject(o3);
}

private static final class MyPooledObject extends AbstractPooledObject {

private final int id;
Expand Down