jam2in / arcus-java-client Goto Github PK
View Code? Open in Web Editor NEWThis project forked from naver/arcus-java-client
Arcus Java client
License: Apache License 2.0
This project forked from naver/arcus-java-client
Arcus Java client
License: Apache License 2.0
commit - push 하기 전에 간단한 lint 확인을 위한 pre-commit scripts 를 추가한다.
해당 내용은 8.3 Git맞춤 - Git Hooks에 자세하게 설명되어 있다.
현재 arcus-java-client 의 .git directory 아래에는 hooks 가 없는 상태이다.
pre-commit scripts 에서는 [Java/C Client] Coding Style Guide 작성 이슈에서 논의된 내용을 바탕으로 작성된 Jam2in Java Coding Style Guide 의 내용을 점검한다.
그 외에도 lint 검사로 추가할 것이 있으면 논의를 통해 추가한다.
ClientBaseCase 의 CFB class 에 설계상 오류가 존재합니다.
ClientBaseCase 의 CFB 의 본래 목적은
각 junit test 에서 test 성격에 맞는 설정을 갖는 ConnectionFactory 를 생성하고.
이것을 CFB에 넘겨주면 이것 이외에는 DefaultConnectionFactory 의 값을 사용하도록 하기 위함입니다.
아래 코드를 보시면 이해가 쉽습니다.
ClientBaseCase.java
protected void initClient() throws Exception {
initClient(new DefaultConnectionFactory() {
@Override
public long getOperationTimeout() {
return 15000;
}
@Override
public FailureMode getFailureMode() {
return FailureMode.Retry;
}
});
}
protected void initClient(ConnectionFactory cf) throws Exception {
if (USE_ZK) {
openFromZK(new CFB(cf));
} else {
openDirect(new CFB(cf));
}
}
ClientBaseCase.CFB
private static class CFB extends ConnectionFactoryBuilder {
private final ConnectionFactory inner;
public CFB(ConnectionFactory cf) {
this.inner = cf;
}
@Override
public ConnectionFactory build() {
return new ConnectionFactory() {
@Override
public MemcachedConnection createConnection(
List<InetSocketAddress> addrs) throws IOException {
return inner.createConnection(addrs);
}
...
@Override
public Collection<ConnectionObserver> getInitialObservers() {
return inner.getInitialObservers();
}
...
};
}
@Override
public ConnectionFactoryBuilder setInitialObservers(
Collection<ConnectionObserver> obs) {
return this;
}
}
하지만 설계(?)의 문제로 인하여 본래의 의도대로 코드가 동작하지 않습니다.
정확히는 대부분의 코드는 문제가 되지 않지만, 특정 부분에서 문제가 발생합니다.
그 중에 하나가 CFB 의 inner.createConnection(addrs) 입니다.
여기서의 inner 는 ClientBaseCase.initClient() 에서 생성된 DefaultConnectionFactory 인데, createConnection 코드를 보면 아래와 같습니다.
DefaultConnectionFactory.java
public MemcachedConnection createConnection(List<InetSocketAddress> addrs)
throws IOException {
return new MemcachedConnection(getReadBufSize(), this, addrs,
getInitialObservers(), getFailureMode(), getOperationFactory());
}
여기서 getInitialObservers() 는 코드상 무조건 아래 코드입니다.
DefaultConnectionFactory.getinitialObservers
public Collection<ConnectionObserver> getInitialObservers() {
return Collections.emptyList();
}
이렇게 되면 USE_ZK=true 로 테스트 코드를 실행할 경우,
CacheManager.createArcusClient() 에서 latch 때문에 10초를 대기하게 됩니다.
이러한 문제는 DefaultConnectionFactory 에는 멤버 변수이 기본 값을 return 하면서,
ConnectionFactoryBuilder 의 멤버 변수에 set 을 한 뒤 get 을 하는 설정 들은 모두 문제가 됩니다.
그 예가 initial observers 입니다.
설명이 좀 어렵지만 코드를 찬찬히 읽어보시면 이해가 될 것 같습니다.
현재 발견한 문제는 observers 만 발생하지만 다른 connection config 에도 문제가 될 수 있습니다.
ClientBaseCase 의 CFB 만 수정하거나 ClientBaseCase.initClient(ConnectionFactory cf) 만 수정해서는 해결할 문제가 아니고,
ClientBaseCase 를 상속받아 initClient(ConnectionFactory cf) 를 사용하는 모든 테스트를 수정해야 합니다.
replication 기능이 없는 경우의 updateConnection() 코드입니다.
Remove할 node에 있던 operations들에 대해 모두 cancel 처리를 해 줘야 할 것 같은데,
reading state에 있는 operations에 대해서는 cancel 처리 하지 않고 있습니다..
응용에서 operation timeout으로 cancel하는 것이 대부분이겠지만,
응용에서 무한히 대기하는 경우도 있을 수 있으므로,
이 부분에서 cancel 처리하는 것이 맞지 않나요 ??
for (MemcachedNode node : locator.getAll()) {
if (addrs.contains((InetSocketAddress) node.getSocketAddress())) {
addrs.remove((InetSocketAddress) node.getSocketAddress());
} else {
removeNodes.add(node);
}
}
// Make connections to the newly added nodes.
for (SocketAddress sa : addrs) {
attachNodes.add(attachMemcachedNode(sa));
}
// Update the hash.
locator.update(attachNodes, removeNodes);
// Remove unavailable nodes in the reconnect queue.
for (MemcachedNode node : removeNodes) {
getLogger().info("old memcached node removed %s", node);
for (Entry<Long, MemcachedNode> each : reconnectQueue.entrySet()) {
if (node.equals(each.getValue())) {
reconnectQueue.remove(each.getKey());
break;
}
}
String cause = "node removed.";
if (failureMode == FailureMode.Cancel) {
cancelOperations(node.destroyWriteQueue(false), cause);
cancelOperations(node.destroyInputQueue(), cause);
} else if (failureMode == FailureMode.Redistribute || failureMode == FailureMode.Retry) {
redistributeOperations(node.destroyWriteQueue(true), cause);
redistributeOperations(node.destroyInputQueue(), cause);
}
}
Boxing
타입은 Java 9 이후로 new 생성자
를 이용하는 것이 deprecated
되었습니다.
최신 버전의 Java와의 호환성을 위해 valueOf
메서드를 활용하는 편이 것이 좋을 것 같습니다.
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/SerializingTranscoder.java:[86,16] Integer(int) in java.lang.Integer has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/SerializingTranscoder.java:[89,16] Long(long) in java.lang.Long has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/SerializingTranscoder.java:[95,16] Byte(byte) in java.lang.Byte has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/SerializingTranscoder.java:[98,16] Float(float) in java.lang.Float has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/SerializingTranscoder.java:[101,16] Double(double) in java.lang.Double has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/ArcusClient.java:[1751,22] Integer(java.lang.String) in java.lang.Integer has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/ArcusClient.java:[4437,24] Long(java.lang.String) in java.lang.Long has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/CollectionTranscoder.java:[89,16] Integer(int) in java.lang.Integer has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/CollectionTranscoder.java:[92,16] Long(long) in java.lang.Long has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/CollectionTranscoder.java:[98,16] Byte(byte) in java.lang.Byte has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/CollectionTranscoder.java:[101,16] Float(float) in java.lang.Float has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/CollectionTranscoder.java:[104,16] Double(double) in java.lang.Double has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/WhalinTranscoder.java:[66,16] Integer(int) in java.lang.Integer has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/WhalinTranscoder.java:[69,16] Short(short) in java.lang.Short has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/WhalinTranscoder.java:[72,16] Long(long) in java.lang.Long has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/WhalinTranscoder.java:[78,16] Byte(byte) in java.lang.Byte has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/WhalinTranscoder.java:[81,16] Float(float) in java.lang.Float has been deprecated and marked for removal
[WARNING] /Users/jam2in/workspace/arcus-java-client/src/main/java/net/spy/memcached/transcoders/WhalinTranscoder.java:[84,16] Double(double) in java.lang.Double has been deprecated and marked for removal
Java 17 버전 기준으로 컴파일하는 경우 위와 같은
WARNING
이 발생
아래 코드는 net.spy.memcached.transcoders.SerializingTranscoder
의 decode 메서드입니다.
public Object decode(CachedData d) {
// ...
case SPECIAL_INT:
rv = new Integer(tu.decodeInt(data));
break;
case SPECIAL_LONG:
rv = new Long(tu.decodeLong(data));
break;
// ...
}
public Object decode(CachedData d) {
// ...
case SPECIAL_INT:
rv = Integer.valueOf(tu.decodeInt(data));
break;
case SPECIAL_LONG:
rv = Long.valueOf(tu.decodeLong(data));
break;
// ...
}
Spring Data Arcus의 자바 버전을 17로 설정하기 위해서는 ARCUS Java Client 또한 17 버전의 컴파일을 지원해야 합니다.
해당 문제 이외에 자바 17버전 컴파일러에서 발생하는 WARNING이 없는 것으로 보아, 해당 이슈만 해결된다면 호환성 문제는 없을 것 같습니다.
연속된 2개 이상의 연산의 get 연산이어야 optimize 할 수 있을 건데요..
그러면, 처음에 writeQ.remove()한 operation은 처리되지 않을 것 같은 데, 버그 아닌가요 ?
protected void optimize() {
// make sure there are at least two get operations in a row before
// attempting to optimize them.
if(writeQ.peek() instanceof GetOperation) {
optimizedOp=writeQ.remove();
if(writeQ.peek() instanceof GetOperation) {
OptimizedGetImpl og=new OptimizedGetImpl(
(GetOperation)optimizedOp);
optimizedOp=og;
while(writeQ.peek() instanceof GetOperation) {
GetOperationImpl o=(GetOperationImpl) writeQ.remove();
if(!o.isCancelled()) {
og.addOperation(o);
}
}
// Initialize the new mega get
optimizedOp.initialize();
assert optimizedOp.getState() == OperationState.WRITING;
ProxyCallback pcb=(ProxyCallback) og.getCallback();
getLogger().debug("Set up %s with %s keys and %s callbacks",
this, pcb.numKeys(), pcb.numCallbacks());
}
}
}
테스트 함수들 중 ~~~UsingSingleClient() 코드의 목적이 불분명하고, 코드 중복이 일어나고 있어 삭제하기로 결정함.
arcus client pool 을 사용하는 경우와 단일 arcus client 를 사용하는 경우로 나누어 테스트하려고 했던 것으로 추측되나, ArcusClientPool 의 경우 모든 API 호출이 this.getClient().~~~() 호출로 이어지기 때문에 굳이 나누어 테스트하는 것이 불필요하다고 판단됨.
응용이 요청한 operations이 아래 queue 중에 있을 시에 언제 queue에서 인지되고 빠지는 가를 확인.
CollectionAttributes에 만료기간만 정한 후 insert에 해당 attribute를 넣어 생성과 함께 필드를 할당하면,
이후 다시 가져왔을 때 가장 먼저 집어넣은 키, 값 중 값의 클래스로 고정되어 인식됩니다. 실제 케이스에선 Long이 가장 먼저 삽입되었습니다.
정상적인 방법으로 OTHERS 타입으로 생성 및 값 입력
creationTime 6
maxInactiveTime 2 %^&$(인코딩 실패)
lastAaccessedTime 6 %^&$(인코딩 실패)
실제 자료형은 각각
long, integer, long 순입니다.
으로 입력되었으며 caught ioexception decoding 2(위 예시의 숫자) bytes of data가 항목마다 발생했습니다.
조치방법: STRING형으로 생성 후, JSON으로 직렬화 후 가져올 때마다 다시 역직렬화하는 방식으로 대체했습니다.
다수 연산을 수행함에 있어, 아래 두 방식의 성능과 개발 편이성 비교..
replication / 기타 추가 기능에 대한 테스트 케이스 추가
아래 코드에서 bytesToCopy는 아래 둘 중의 작은 값으로 설정해야 하지 않나요 ?
public final void fillWriteBuffer(boolean shouldOptimize) {
if(toWrite == 0 && readQ.remainingCapacity() > 0) {
getWbuf().clear();
Operation o=getCurrentWriteOp();
while(o != null && toWrite < getWbuf().capacity()) {
assert o.getState() == OperationState.WRITING;
// This isn't the most optimal way to do this, but it hints
// at a larger design problem that may need to be taken care
// if in the bowels of the client.
// In practice, readQ should be small, however.
if(!readQ.contains(o)) {
readQ.add(o);
}
ByteBuffer obuf=o.getBuffer();
assert obuf != null : "Didn't get a write buffer from " + o;
int bytesToCopy=Math.min(getWbuf().remaining(),
obuf.remaining());
byte b[]=new byte[bytesToCopy];
obuf.get(b);
getWbuf().put(b);
getLogger().debug("After copying stuff from %s: %s",
o, getWbuf());
if(!o.getBuffer().hasRemaining()) {
o.writeComplete();
transitionWriteItem();
preparePending();
if(shouldOptimize) {
optimize();
}
o=getCurrentWriteOp();
}
toWrite += bytesToCopy;
}
getWbuf().flip();
assert toWrite <= getWbuf().capacity()
: "toWrite exceeded capacity: " + this;
assert toWrite == getWbuf().remaining()
: "Expected " + toWrite + " remaining, got "
+ getWbuf().remaining();
} else {
getLogger().debug("Buffer is full, skipping");
}
}
OperationImpl.matchStatus 내에 아래와 같은 코드가 있다.
if(rv == null) {
rv=new OperationStatus(false, line);
/* ENABLE_REPLICATION if */
getLogger().error("Unexpected operation status : %s", line);
/* ENABLE_REPLICATION end */
}
위 코드는 replication 개발 당시 debug 를 위해 추가했던 내용이다.
실제 배포 시에 제거되었어야 하는 코드인데, 그대로 배포되었다.
삭제하도록 한다.
travis CI 테스트 도중 아래와 같은 문제가 있어 이슈 남깁니다.
testTimeout() 테스트가
request 를 날린 다음, 바로 future.get 을 수행하는데 timeout 을 1ms 또는 1ns 로 아주 짧게 주어
타임아웃 발생을 유도하는 방식입니다.
상황에 따라 다른 것 같긴 한데 현재까지 확인한 바로는
BopInsertBulkTest.testTimeout()
FlushByPrefixTest.testTimeout()
의 future.get()
에서 타임아웃이 발생하지 않아 테스트 Failure 되는 사례가 있었습니다.
모든 테스트 클래스의 testTimeout() 테스트에 대해 재고가 필요할 것 같습니다.
[Clients] ketama hash collision 시의 owner 결정 이슈 사항입니다.
이슈 내용입니다.
여러 노드의 160 hash point 중에 서로 collistion 발생 시,
- node의 name string 대소 비교하여,
- 더 작은 name string을 가진 노드가 그 hash point에 대한 ownership을 가지게 처리
현재 cache server 쪽은 처리 완료한 상태이며, 최소한 Java/C clients에서 처리가 필요합니다.
참고로, python, ruby 등의 arcus client에서도 한번 확인해 주면 좋겠습니다.
아래는 setupResend() 코드입니다..
public final void setupResend(boolean cancelWrite, String cause) {
// First, reset the current write op, or cancel it if we should
// be authenticating
Operation op=getCurrentWriteOp();
if((cancelWrite || shouldAuth) && op != null) {
op.cancel(cause);
} else if(op != null) {
ByteBuffer buf=op.getBuffer();
if(buf != null) {
buf.reset();
} else {
getLogger().info("No buffer for current write op, removing");
removeCurrentWriteOp();
}
}
// Now cancel all the pending read operations. Might be better to
// to requeue them.
while(hasReadOp()) {
op=removeCurrentReadOp();
if (op != getCurrentWriteOp()) {
getLogger().warn("Discarding partially completed op: %s", op);
op.cancel(cause);
}
}
while((cancelWrite || shouldAuth) && hasWriteOp()) {
op=removeCurrentWriteOp();
getLogger().warn("Discarding partially completed op: %s", op);
op.cancel(cause);
}
getWbuf().clear();
getRbuf().clear();
toWrite=0;
}
cancelWrite = true인 경우,
이상한 부분은current write op에 대해 2회 cancel 처리이며,
1회 cancel 처리로 변경되어야 할 것 같습니다.
추가로, cancel 처리하는 op에 대해 buffer != null이더라도 reset 처리는 필요 없는 거죠 ?
cancelWrite = false인 경우,
이상한 부분은 위의 2번째 처리 로직이며,
그 op를 제거하지 않아야 할 것 같습니다.
오히려, 그 op의 initialize() 메소드를 호출해야 하지 않는 지요 ?
operation timeout 발생 시 아래와 같이 로그가 출력되고 있습니다.
net.spy.memcached.internal.CheckedOperationTimeoutException: Timed out waiting for operation. >3 - failing node: /10.144.146.17:11211 [READING] [#
Tops=406766 #iq=1 #Wops=0 #Rops=1 #CT=1 #TR=-1]
위에서 3이라는 timeout 값이 어떤 단위를 사용하고 있는지 전혀 알 수 없는 상태입니다.
로그에서 TimeUnit 값을 함께 출력하는 것이 분석에 도움이 될 것 같습니다.
arcus-java-client API를 아래 관점에서 재검검한다.
Backward compatiliity 문제로 쉽게 변경하지 못하겠지만,
한번 정리해 두면 좋을 것 같습니다.
asyncGetAttr 수행 시, cache server는 정상 response string을 던지지만 java client는 아래와 같은 메세지를 출력합니다.
2016-08-17 11:12:27.359 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.360 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.360 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.361 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.362 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.362 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.365 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.365 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.366 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.367 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.367 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.368 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.369 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.370 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.370 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.371 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.372 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.372 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.374 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.375 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.376 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR expiretime=0
2016-08-17 11:12:27.377 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR type=kv
2016-08-17 11:12:27.377 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR flags=0
2016-08-17 11:12:27.378 ERROR net.spy.memcached.protocol.ascii.GetAttrOperationImpl: Unexpected operation status : ATTR expiretime=0
...
java client에서 replication 사용하기 위해서는 해당 replication flag를 설정해야 합니다.
이러한 불편함이 replication 적용에 하나의 장벽이 되는 건지 다시 한번 논의해 봅시다.
본 이슈는 "[Java Client] switchover에서 reading operation 처리 개선"https://github.com/jam2in/arcus-task/issues/84 에서 처리하던 것을 옮겨왔습니다.
자세한 히스토리는 본래 이슈를 참고하시면 됩니다.
modify that next index will be processed when bulk and pipe opeartion moved by switchover
commit : 0de1c2e
issue 및 commit에서 빠진 부분이 있어서 추가 합니다.
CollectionPipedUpdate btree 부분 수정이 필요합니다.
USE_ZK 옵션 필요 여부에 대한 논의가 필요합니다.
현재는 USE_ZK=false 일 경우에도, ZK_HOST / ZK_SERVICE_CODE 를 환경에 맞게 설정해 주어야 mvn test 가 성공합니다.
참조 : maven test 관련 이슈
ARCUS 솔루션 자체가 ZK 를 내부적으로 포함하고 있는 구조이니, USE_ZK 를 없애고 default true 로 가져갈지, 아니면 ZK 없이 arcus-memcached 를 단독으로 사용하는 경우까지를 배려할지에 대해 논의가 필요합니다.
지금까지 수동으로 수행하는 mvn test 에 의존하고 있었는데, 효율적인 개발 진행을 위해서 CI 환경 구축이 도움이 많이 될 것 같습니다. 도입에 들어가는 코스트나 러닝커브는 조금 있겠지만, 장기적으로 보았을 때 실보다는 득이 많으리라 판단됩니다. 저도 CI 에 대해서 이론적으로나 실무적으로나 아는 것이 거의 없는 터라 조금씩이라도 내용 찾아보고 공유하도록 하겠습니다. 코드 보다가 다른 일 하고 싶을때 한번씩 의견 달아주세요 😄
java client 전체적으로 debug log 를 출력할 때 아래와 같이 두 가지 방식을 혼용하고 있다.
한 가지 방식으로 통일한다.
getLogger().debug("Got line %s", line);
if (getLogger().isDebugEnabled()) {
getLogger().debug("Got line %s", line);
}
Server 의 Migration 동작에 맞춰 client 에 기능을 추가한다.
(본 이슈는 Server 의 개발 진척에 따라 점진적으로 이슈의 내용을 아래에 추가/완성해 나가는 것으로 한다.)
arcus-java-client, arcus-c-client에서
Element Flag Filter 사용 시 command line 을 어떻게 보내는지 확인하고,
최대 eflag를 주었을 때 어떻게 처리되는지 확인이 필요하다.
현재 ElementMultiFlagsFilter로 최대 100개 compare value를 지정할 수 있다.
100개의 compare value를 지정 했을 때 command line을 확인해 서버에서 처리 가능한 형태로
command를 만들어서 보내주는지에 대한 확인 작업이다.
setArcusReplEnabled 플래그를 사용하며 응용에서 정확한 message를 받지 못해 헷갈려하는 경우가 잦다.
replication 을 사용하던지 안하던지 serviceCode를 정해진 설정에서 찾지 못한다면 양쪽을 다 확인하여 replication 플래그를 잘못설정한 게 아닌지에 대한 메시지를 던지도록 변경해야한다.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.