new ISODate\("([A-Z0-9\-:.]{24,24})"\)

 

new NumberInt\("([0-9]{1,10})"\)

'Develop' 카테고리의 다른 글

WebClient 에러 처리  (0) 2023.01.10
Protobuf reserved  (0) 2022.06.25
젠킨스 파이프라인에서 다른 job 실행  (0) 2022.04.01
mysql rows to columns  (0) 2021.10.21
DocumentDB failover 장애 시간  (0) 2021.09.28

request 개별 적용

webClient.get()
    .uri { uriBuilder ->
        uriBuilder.path("/v1/~~~~~")
            .queryParam("aaa", 11)
            .queryParam("bbb", 222)
            .build()
    }
    .retrieve()
	.onStatus(HttpStatus::is5xxServerError) {
        val response = it.bodyToMono<Coupon.ErrorResponse>().block()
        Mono.error(HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR, response.detailMessage ?: ""))
    }
    .awaitBody<List<ResponseItem>>()

 

webclient 적용

ExchangeFilterFunction.ofResponseProcessor { clientResponse: ClientResponse ->
    if (clientResponse.statusCode().is5xxServerError) {
        return@ofResponseProcessor clientResponse.bodyToMono(String::class.java)
            .flatMap { errorBody: String? ->
                val body = objectMapper.readValue(errorBody, ErrorResponse::class.java)
                Mono.error(
                    HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR, body.detailMessage ?: "")
                )
            }
    } else {
        return@ofResponseProcessor Mono.just(clientResponse)
    }
}

 

'Develop' 카테고리의 다른 글

몽고에 저장되는 json에 쓸수 있는 정규 표현식  (0) 2023.08.10
Protobuf reserved  (0) 2022.06.25
젠킨스 파이프라인에서 다른 job 실행  (0) 2022.04.01
mysql rows to columns  (0) 2021.10.21
DocumentDB failover 장애 시간  (0) 2021.09.28

목적

protobuf 에서

reserved, 필드 삭제를 했을 때의 변화를 관찰하고,

왜 필드 삭제가 아닌 reserved를 해야 하는지를 알아본다.



protobuf 문서

 



상황별 비교

 

  기본 reserved delete
proto message TestRequest {
  int32 m1 = 1;
  string m2 = 2;
  int64 m3 = 3;
  int32 m4 = 4;
  string m5 = 5;
  int32 m6 = 6;
  string m7 = 7;
  int64 m8 = 8;
  int32 m9 = 9;
  string m10 = 10;
}
message TestRequest {
  int32 m1 = 1;
  string m2 = 2;
  int64 m3 = 3;
  reserved 4;
  string m5 = 5;
  int32 m6 = 6;
  reserved 7;
  int64 m8 = 8;
  int32 m9 = 9;
  string m10 = 10;
}
message TestRequest {
  int32 m1 = 1;
  string m2 = 2;
  int64 m3 = 3;


  string m5 = 5;
  int32 m6 = 6;


  int64 m8 = 7;
  int32 m9 = 8;
  string m10 = 9;
}
generated code boolean done = false;
while (!done) {
  int tag = input.readTag();
  switch (tag) {
    case 0:
      done = true;
      break;
    case 8:
      {

        m1_ = input.readInt32();
        break;
      }
    case 18:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m2_ = s;
        break;
      }
    case 24:
      {

        m3_ = input.readInt64();
        break;
      }
    case 32:
      {

        m4_ = input.readInt32();
        break;
      }
    case 42:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m5_ = s;
        break;
      }
    case 48:
      {

        m6_ = input.readInt32();
        break;
      }
    case 58:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m7_ = s;
        break;
      }
    case 64:
      {

        m8_ = input.readInt64();
        break;
      }
    case 72:
      {

        m9_ = input.readInt32();
        break;
      }
    case 82:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m10_ = s;
        break;
      }
    default:
      {
        if (!parseUnknownField(
            input, unknownFields, extensionRegistry, tag)) {
          done = true;
        }
        break;
      }
  }
}
boolean done = false;
while (!done) {
  int tag = input.readTag();
  switch (tag) {
    case 0:
      done = true;
      break;
    case 8:
      {

        m1_ = input.readInt32();
        break;
      }
    case 18:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m2_ = s;
        break;
      }
    case 24:
      {

        m3_ = input.readInt64();
        break;
      }
    case 42:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m5_ = s;
        break;
      }
    case 48:
      {

        m6_ = input.readInt32();
        break;
      }
    case 64:
      {

        m8_ = input.readInt64();
        break;
      }
    case 72:
      {

        m9_ = input.readInt32();
        break;
      }
    case 82:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m10_ = s;
        break;
      }
    default:
      {
        if (!parseUnknownField(
            input, unknownFields, extensionRegistry, tag)) {
          done = true;
        }
        break;
      }
  }
boolean done = false;
while (!done) {
  int tag = input.readTag();
  switch (tag) {
    case 0:
      done = true;
      break;
    case 8:
      {

        m1_ = input.readInt32();
        break;
      }
    case 18:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m2_ = s;
        break;
      }
    case 24:
      {

        m3_ = input.readInt64();
        break;
      }
    case 42:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m5_ = s;
        break;
      }
    case 48:
      {

        m6_ = input.readInt32();
        break;
      }
    case 64:
      {

        m8_ = input.readInt64();
        break;
      }
    case 72:
      {

        m9_ = input.readInt32();
        break;
      }
    case 82:
      {
        java.lang.String s = input.readStringRequireUtf8();

        m10_ = s;
        break;
      }
    default:
      {
        if (!parseUnknownField(
            input, unknownFields, extensionRegistry, tag)) {
          done = true;
        }
        break;
      }
  }



serialized data

입력

 

m1 = 43690

m2 = "abcdefg"

m3 = 1431655765

m4 = 43690

m5 = "hijklmn"

m6 = 43690

m7 = "hijklmn"

m8 = 1431655765

m9 = 43690

m10 = "opqrstu"

 

출력

 

기본 reserved delete
08 AAD502
12 07 61626364656667
18 D5AAD5AA05
20 AAD502
2A 07 68696A6B6C6D6E
30 AAD502
3A 07 68696A6B6C6D6E
40 D5AAD5AA05
48 AAD502
52 07 6F707172737475
08 AAD502
12 07 61626364656667 
18 D5AAD5AA05

2A 07 68696A6B6C6D6E
30 AAD502

40 D5AAD5AA05
48 AAD502
52 07 6F707172737475
08 AAD502
12 07 61626364656667
18 D5AAD5AA05

2A 07 68696A6B6C6D6E
30 AAD502

40 D5AAD5AA05
48 AAD502
52 07 6F707172737475





결론

  1. 이미 stub이 배포 된 .proto 에서 필드를 제거 할 땐, reserved를 이용하자.
  2. 절대로 property number는 변경하지 말자.




추가

optional일 때는?



default optional
message TestRequest {
  int32 m1 = 1;
  int32 m2 = 2;
  int32 m3 = 3;
}
message OptionalTest {
int32 m1 = 1;
optional int32 m2 = 2;
int32 m3 = 3;
}
boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
  case 0:
    done = true;
    break;
  case 8:
    {

      m1_ = input.readInt32();
      break;
    }
  case 16:
    {

      m2_ = input.readInt32();
      break;
    }
  case 24:
    {

      m3_ = input.readInt32();
      break;
    }
  default:
    {
      if (!parseUnknownField(
          input, unknownFields, extensionRegistry, tag)) {
        done = true;
      }
      break;
    }
}
}

boolean done = false;
while (!done) {
int tag = input.readTag();
switch (tag) {
  case 0:
    done = true;
    break;
  case 8:
    {

      m1_ = input.readInt32();
      break;
    }
  case 16:
    {
      bitField0_ |= 0x00000001;
      m2_ = input.readInt32();
      break;
    }
  case 24:
    {

      m3_ = input.readInt32();
      break;
    }
  default:
    {
      if (!parseUnknownField(
          input, unknownFields, extensionRegistry, tag)) {
        done = true;
      }
      break;
    }
}
}

 

optional 일 때 추가되는 것들



default optional


private int m1_;







public int getM1() {
  return m1_;
}


public Builder setM1(int value) {
  m1_ = value;
  onChanged();
  return this;
}

public Builder clearM1() {
  m1_ = 0;
  onChanged();
  return this;
}

private int bitField0_;

private int m2_;

public boolean hasM2() {
return ((bitField0_ & 0x00000001) != 0);
}

public int getM2() {
return m2_;
}

public Builder setM2(int value) {
bitField0_ |= 0x00000001;
m2_ = value;
onChanged();
return this;
}

public Builder clearM2() {
bitField0_ = (bitField0_ & ~0x00000001);
m2_ = 0;
onChanged();
return this;
}

 

1. 파이프라인 생성.

 

 

2. 호출 될 Job 생성

 

 

3. 파이프라인 설정 

파이프라인 스크립터 문법

pipeline {
    agent any 
    stages 
    {
        stage('Start') {
            steps {
                echo 'Hello'
            }
        }
        stage ('Invoke_testA') {
            steps {
                build job: 'testA', parameters: []
            }
        }
        stage ('Invoke_testB') {
            steps {
                build job: 'testB', parameters: []
            }
        }
        stage('End') {
            steps {
                echo 'Bye'
            }
        }
    }
}

 

4. 실행 결과

'Develop' 카테고리의 다른 글

WebClient 에러 처리  (0) 2023.01.10
Protobuf reserved  (0) 2022.06.25
mysql rows to columns  (0) 2021.10.21
DocumentDB failover 장애 시간  (0) 2021.09.28
nodeJs Buffer  (0) 2021.04.09

https://stackoverflow.com/questions/1241178/mysql-rows-to-columns

 

MySQL - Rows to Columns

I tried to search posts, but I only found solutions for SQL Server/Access. I need a solution in MySQL (5.X). I have a table (called history) with 3 columns: hostid, itemname, itemvalue. If I do a ...

stackoverflow.com

 

select
  d2.host_id,
  ifnull(sum(d2.A),0) as A,
  ifnull(sum(d2.B),0) as B,
  ifnull(sum(d2.C),0) as C
from
  (select
    demo2.*,
    case when item_name='A' then item_value end as A,
    case when item_name='B' then item_value end as B,
    case when item_name='C' then item_value end AS C
 	 from demo2) AS d2
GROUP by d2.host_id;

 

'Develop' 카테고리의 다른 글

Protobuf reserved  (0) 2022.06.25
젠킨스 파이프라인에서 다른 job 실행  (0) 2022.04.01
DocumentDB failover 장애 시간  (0) 2021.09.28
nodeJs Buffer  (0) 2021.04.09
aws elasticcache MOVED 문제  (0) 2021.02.02

DocumentDB를 추가, 삭제, rename 하면서 발생한 장애시간

 

새로 추가 할 때: connect ECONNREFUSED 에러가 1분 내

rename 할 때: getaddrinfo ENOTFOUND 에러가 1분 내

delete 할 때: MongooseServerSelectionError 에러가 8분 정도 지속

 

failover를 발생시키는 명령어로 master, slave가 바뀔때는 에러가 발생하지 않았다.

하지만 물리적인 서버의 문제로 failover가 발생한다면, 접속 관련 에러가 발생 할 것으로 예상된다.

'Develop' 카테고리의 다른 글

젠킨스 파이프라인에서 다른 job 실행  (0) 2022.04.01
mysql rows to columns  (0) 2021.10.21
nodeJs Buffer  (0) 2021.04.09
aws elasticcache MOVED 문제  (0) 2021.02.02
make date range list  (0) 2020.07.03

금융사와 tcp 통신을 해야 할 업무가 생겼는데,

10년전 게임 만들 때 사용하던 것처럼 binary배열에 바이트를 할당해서 사용할 일이 생겼다.

그리고 nestjs 서버간 Buffer를 주고 받아야 할일이 생겼는데, 거기서 문제가 생겼다.

 

그에 관련된 얘기를 하고자 한다.

 

조금 벗어난 얘기를 하자면, 

정의된 클래스 -> Buffer

Buffer -> 정의된 클래스 로 변환할 때는 struct 패키지를 사용했다.

www.npmjs.com/package/struct

 

struct

Pack/Unpack multibyte binary values from/to buffers

www.npmjs.com

 

개발환경

typescript, nestjs

 

처음에는 기존에 했던 데로 class로 request, response를 정의했다.

각 request, response 에는 Buffer가 property로 들어있다.

 

이 Buffer를 주고 받을 때 발생한 문제인데,

 

class에 Buffer를 property로 넣고 요청을 하면 JSON으로 변환되서 전달된다.

전달 받은 서버에서는 JSON을 Buffer로 변환되리라 기대 했지만,

그렇지 않다. 

 

해결 방법은 Uint8Array를 이용하는 방법도 있지만,

쉬운길을 택했다.

Buffer -> base64로 인코딩 후 전송, base64 -> Buffer 로 디코딩 후 사용한다.

 

코드를 보면 쉽게 이해가 가능하다.

 

const a = Buffer.from("abcdef")

console.log(a)
// <Buffer 61 62 63 64 65 66>

console.log(a.toJSON())
// { type: 'Buffer', data: [ 97, 98, 99, 100, 101, 102 ] }

const b = a.toString("base64")
console.log(b)
// YWJjZGVm

const c = Buffer.from(b, "base64")
console.log(c)
// <Buffer 61 62 63 64 65 66>

console.log(c.toString())
// abcdef

'Develop' 카테고리의 다른 글

mysql rows to columns  (0) 2021.10.21
DocumentDB failover 장애 시간  (0) 2021.09.28
aws elasticcache MOVED 문제  (0) 2021.02.02
make date range list  (0) 2020.07.03
ecs-params: assign_public_ip  (0) 2020.06.02

클라이언트가 cluster로 인식 못했을 때 발생하는 문제라고 한다.

readonly 명령어를 사용하면 get은 된다.

 

클라이언트를 cluster 모드로 사용 하자.

 

-c                 Enable cluster mode (follow -ASK and -MOVED redirections).

 

redis-cli -c -h xxxxx

'Develop' 카테고리의 다른 글

DocumentDB failover 장애 시간  (0) 2021.09.28
nodeJs Buffer  (0) 2021.04.09
make date range list  (0) 2020.07.03
ecs-params: assign_public_ip  (0) 2020.06.02
node packages github branch로 사용  (0) 2020.05.26
function getRangeOfDates(start: moment.Moment, end: moment.Moment, key: moment.DurationInputArg2, arr = [start.startOf(key)]): moment.Moment[] {
	if(start.isAfter(end)) throw new Error("start must precede end")
	const next = moment(start).add(1, key).startOf(key)
	if(next.isAfter(end, key)) return arr
	return getRangeOfDates(next, end, key, arr.concat(next))
}

 

출처 : https://gist.github.com/miguelmota/7905510

'Develop' 카테고리의 다른 글

nodeJs Buffer  (0) 2021.04.09
aws elasticcache MOVED 문제  (0) 2021.02.02
ecs-params: assign_public_ip  (0) 2020.06.02
node packages github branch로 사용  (0) 2020.05.26
mysql index hint  (0) 2020.03.26

환경: ecs-fargate, kinesis, sqs 사용

문제 상황: ecs에서 kinesis와 sqs 접속이 잘되었는데 언제부턴가 안된다.

변경점: 외부 접속이 필요 없는 worker로써의 app이기 때문에 assign_public_ip 옵션을 DISABLED로 수정함.

해결방법: 다시 ENABLED로 바꾸니 잘됨.

 

 

AWS 공식 문서
assign_public_ip – 이 필드에 사용할 수 있는 값은 ENABLED 또는 DISABLED입니다. 이 필드는 Fargate 시작 유형을 사용하는 작업에서만 사용됩니다. EC2 시작 유형이고 작업 네트워킹을 사용하는 작업에 이 필드가 있는 경우, 요청은 실패합니다.

이렇게 적혀있다.

 

의미하는게 뭐지.. 그냥 필수값인건가..

'Develop' 카테고리의 다른 글

aws elasticcache MOVED 문제  (0) 2021.02.02
make date range list  (0) 2020.07.03
node packages github branch로 사용  (0) 2020.05.26
mysql index hint  (0) 2020.03.26
The CloudFormation template is invalid  (0) 2020.01.14

+ Recent posts