개인 프로젝트에서 nginx를 웹서버로 사용하고 있다. 그 뒤에는 2대의 WAS를 사용하고 있고, nginx upstream 기능을 사용하여 로드 밸런싱을 했다. 그러다 보니 배포시에 아래 upstream 내 server를 주석처리하고 nginx 를 reload 하고 다 배포하고 또 주석 처리하고 nginx reload하고.... 다 처리하고 다시 reload하고... 휴.... 반복 해야 한다. 


upstream.conf

upstream project_was {
least_conn;
server 127.0.0.1:8081 weight=1;
server 127.0.0.1:8080 weight=1;
}


생각보다 이 작업이 시간도 많이 걸리고 사람이 작업을 하다 보니, 실수가 종종 나오곤 했다. 좋은 방법이 없나 고민을 하기 시작했다!



매일 반복적으로 처리하는 업무의 경우, 최대한 자동화를 진행해야 보다 쾌적한 하루를 보낼 수 있다.


위 글처럼 언제나... 귀찮은 일을 반복하는 걸 싫어하기 때문에 방법 찾아보았다.


1.....?

 - Nginx Plus를 구매!

 - https://www.nginx.com/products/pricing/

 - 비싸다.......


다시!!


1. Nginx Upstream 파일을 만들자!

 - 위 upstream.conf 파일도 어찌 보면 단순 텍스트 파일이다.

 

 1) 배포할 서버를 제외하고 Argument로 활성화 시킬 서버를 넣고 위 파일을 새롭게 생성한다.

  - Argument

USE_HOST_INFO_STR=$1

  - 파일 생성

HOSTS=(${USE_HOST_INFO_STR//,/' '})

SERVER_TEXT_TMPL='server HOST weight=1;'
UPSTM_NM_TEXT_TMPL='upstream UPSTM_NM '

UPSTM_NM="tmp_upstream"
BASIC_NGINX_CONF_PATH="/etc/nginx/"
UPSTREAM_CONF_FILE_NM=$UPSTM_NM".conf"

RTN_CONF_STR="${UPSTM_NM_TEXT_TMPL/UPSTM_NM/$UPSTM_NM} { \n"
RTN_CONF_STR+=" least_conn; \n "
for host in ${HOSTS[@]}
do
RTN_CONF_STR+="${SERVER_TEXT_TMPL/HOST/$host} \n"
done
RTN_CONF_STR+="} \n"

echo -e $RTN_CONF_STR > $BASIC_NGINX_CONF_PATH$UPSTREAM_CONF_FILE_NM


2. nginx -t 명령어로 conf파일 valid 체크를 한다.

if nginx -t ; then
echo "=======OK========"
systemctl reload nginx.service
else
echo "=======ERROR========"
exit -1;
fi


3. 전체파일

#!/bin/sh

USE_HOST_INFO_STR=$1

function create_conf_file
{
HOSTS=(${USE_HOST_INFO_STR//,/' '})

SERVER_TEXT_TMPL='server HOST weight=1;'
UPSTM_NM_TEXT_TMPL='upstream UPSTM_NM '

UPSTM_NM="tmp_upstream"
BASIC_NGINX_CONF_PATH="/etc/nginx/"
UPSTREAM_CONF_FILE_NM=$UPSTM_NM".conf"

RTN_CONF_STR="${UPSTM_NM_TEXT_TMPL/UPSTM_NM/$UPSTM_NM} { \n"
RTN_CONF_STR+=" least_conn; \n "
for host in ${HOSTS[@]}
do
RTN_CONF_STR+="${SERVER_TEXT_TMPL/HOST/$host} \n"
done
RTN_CONF_STR+="} \n"

echo -e $RTN_CONF_STR > $BASIC_NGINX_CONF_PATH$UPSTREAM_CONF_FILE_NM
}

function valid_check
{
if nginx -t ; then
echo "=======OK========"
systemctl reload nginx.service
else
echo "=======ERROR========"
exit -1;
fi
}

create_conf_file
valid_check


위 작업을 하면서 쉘 스크립트 작성은 오래 걸리지 않았다. 그러나 프로젝트를 진행하면서 배포를 자동화 해 놓으니 너무 너무 편했다. 


결론!!!!!!!!!!!


 - 반복적인 작업을 자동화하는 습관이 필요하다.

 - 조금만 머리를 쓰면 몸이 편하다!

 - 한번 배포할 때 30초에서 1분 정도 소비되던 반복 작업을 빼니, 좀 더 프로젝트에 집중 할 수 있었다.




* 참고로 위에 스크립트를 업무에 가져다 쓰실 경우 sleep을 충분히 주시기 바랍니다. ^_^ 




1. Jquery Each 

 - API 문서 바로가기

 - 쉽게 말해 반복문이다.


2. Break, Continue란?

 - break 는 반복문을 중지하는 기능

 - continue 는 해당하는 반복구간을 건너뛰는 기능


3. Jquery each에서는??

 1) 요약

  - break는 return false;

  - continue는  return true;

  2) 샘플

   - 소스

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>

<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
</ul>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$("ul li").each(function(index) {

var tmpTxt = $(this).text();

if (tmpTxt == "1") {
console.log("Continue value "+ tmpTxt);
return true;

} else if (tmpTxt == "5") {
console.log("Break value "+ tmpTxt);
return false;
}

console.log("value "+ tmpTxt);

});


</script>
</body>
</html>

  - 결과( <li>6</li>에 해당하는 value값은 출력되지 않는다.)



'프로그래밍 > Javascript' 카테고리의 다른 글

How to detect browser.  (0) 2018.07.23
IOS 버전 관련 처리  (0) 2018.07.20
[Jquery] .each에서 break, continue 구현하기.  (0) 2018.07.02
How to create dynamic a form!  (0) 2018.06.07
javascript replaceAll 사용하기  (0) 2018.03.08
Timer 구현하기  (0) 2017.01.25

1. 현상

 - Spring boot 1.5.14 로 프로젝트를 세팅하는 중 에러 발생.

 - Lombok Annotation 적용해놓은 class에서 컴파일 에러

 - Github 이슈함 검색... 버그...


@Data
@NoArgsConstructor
@AllArgsConstructor
public class Sample {
private String test1;
private String test2;

}


2. 해결법

 - @NoArgsConstructor 를 @Data 보다 위에 선언해야한다.


@NoArgsConstructor
@AllArgsConstructor
@Data
public class Sample {

private String test1;
private String test2;

}


* 관련 문서

https://github.com/rzwitserloot/lombok/issues/1703



1. Filter

public interface Filter {
void doFilter(ServletRequest request, ServletResponse response, FilterChain chain);
}

 1) Filter란?

  - J2EE 표준 스팩

 2) init()

  - 필터 인스턴스 초기화

 3) doFilter()

  - 전/후 처리

 4) destroy()

  - 필터 인스턴스 종료

 

2. Interceptor

 - 소스

public interface HandlerInterceptor {


@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception;

@Override
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
throws Exception;

@Override
public void afterCompletion(
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception;

}

 1) Interceptor란?

  - Spring Framework에서 지원하는 스팩


 2) preHandle()  

  - Controller 전에 호출된다.

  - return 값이 false일 경우 controller 및 다음 postHandle 역시 호출되지 않는다.

  - 인증처리 등을 추가하면 좋다.

  - 요청 로그를 남기기 좋다.


 3) postHandle()

  - Controller가 호출되고 난 뒤 호출된다.

  - Request 값을 변경하는데 사용하면 좋다.

  - View에 공통적으로 값을 추가할 때 사용하면 좋다.


 4) afterCompletion()

  - 뷰 렌더링까지 완료된 후에 호출된다.


3. Filter와 Interceptor 차이점

 1) Filter는 Dispatcher servlet 앞단에서 처리한다. Interceptor는 Controller 시작부터해서 메소드별로 라이프 사이클에 맞게 호출된다.

 2) Interceptor와 다르게 Filter는 web.xml에 설정을 추가한다.



1. thymeleaf-layout-dialect 추가(관련 글)

 1) 기존

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

 2) 변경

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
</dependency>


User Bios - The bio field on the User object is no longer available. If the bio field was set for a person, the value will now be appended to the about field.


1. 문제

 - spring-social-facebook:2.0.3 에서 'PROFILE_FIELDS' 내 bio 필드가 있어서 안됨. (위 내용 참고)

 - https://developers.facebook.com/docs/graph-api/changelog


 1) 해결법

  - 기존소스 

Connection<Facebook> connection = facebookConnectionFactory.createConnection(accessGrant);
Facebook facebook = connection.getApi();
User userProfile = facebook.userOperations().getUserProfile();

 - 변경 소스

Connection<Facebook> connection = facebookConnectionFactory.createConnection(accessGrant);
Facebook facebook = connection.getApi();
String [] fields = { "id", "email", "first_name", "last_name" };
User userProfile = facebook.fetchObject("me", User.class, fields);


2. 가능한 필드

{
"id",
"about",
"age_range",
"birthday",
"context",
"cover",
"currency",
"devices",
"education",
"email",
"favorite_athletes",
"favorite_teams",
"first_name",
"gender",
"hometown",
"inspirational_people",
"installed",
"install_type",
"is_verified",
"languages",
"last_name",
"link",
"locale",
"location",
"meeting_for",
"middle_name",
"name",
"name_format",
"political",
"quotes",
"payment_pricepoints",
"relationship_status",
"religion",
"security_settings",
"significant_other",
"sports",
"test_group",
"timezone",
"third_party_id",
"updated_time",
"verified",
"video_upload_limits",
"viewer_can_send_gift",
"website",
"work"
}


참고 링크

https://stackoverflow.com/questions/39890885/error-message-is-12-bio-field-is-deprecated-for-versions-v2-8-and-higher

1. 동적으로 HTML Form을 생성

<html> 
<head>
</head>
<body>
<script>
generatorForm();

function generatorForm() {
var formEle = document.createElement("form");
formEle.setAttribute('method',"post");
formEle.setAttribute('action',"/action");

var tmpInput = document.createElement("input"); //input element, text
tmpInput.setAttribute('type',"text");
tmpInput.setAttribute('name',"tempValue");

formEle.appendChild(tmpInput);

var submitBtn = document.createElement("input"); //input element, Submit button
submitBtn.setAttribute('type',"submit");
submitBtn.setAttribute('value',"Submit BTN");

formEle.appendChild(submitBtn);

document.body.appendChild(formEle);
}
</script>
</body>
</html>


2. 문제 발생

 1) 에러

document.body.appendChild(formEle);

  - 위 소스를 추가 안할 경우 제대로 동작을 안함. 꼭 추가해야함.


1. Content Type

 - 파일명에 따라 ContentType을 설정한다.


ObjectMetadata objMeta = new ObjectMetadata();
objMeta.setContentType(Mimetypes.getInstance().getMimetype(saveFileNm));


2. Content Length

 - byte length를 추가한다.

ObjectMetadata objMeta = new ObjectMetadata();

byte[] bytes = IOUtils.toByteArray(targetIS);
objMeta.setContentLength(bytes.length);

ByteArrayInputStream byteArrayIs = new ByteArrayInputStream(bytes);

PutObjectRequest putObjReq = new PutObjectRequest(bucketName, key, byteArrayIs, objMeta);
s3client.putObject(putObjReq);

 - 해당 소스처리를 안할 경우 아래와 같은 warning 메시지가 뜬다.

[WARN ] c.a.services.s3.AmazonS3Client:1714 - No content length specified for stream data.  Stream contents will be buffered in memory and could result in out of memory errors.


1. 약수

 -  어떤 수를 나누어 떨어지게 하는 수.


2. Python 소스

if __name__ == "__main__":
number = int(input("숫자를 입력해주세요. : "))

divisors = []

for i in range(1, number + 1):
if number % i == 0:
divisors.append(i)

print(divisors)


'프로그래밍 > Python' 카테고리의 다른 글

10진수 n진수로 변환하기.  (0) 2018.07.30
[Basic] 약수  (0) 2018.06.04

해당 내용은 https://github.com/java-json-tools/json-schema-validator 를 사용하면서 적은 내용입니다.


1. NodeType

{.... "type": "string or array...."}


 - NodeType 목록

 ARRAY("array"),

 BOOLEAN("boolean"),

 INTEGER("integer"),

 NULL("null"),

 NUMBER("number"),

 OBJECT("object"),

 STRING("string")


 - 해당 Library에서는 "com.github.fge.jackson.NodeType"를 참고하시면 편하게 코딩할 수 있다.


2. minItems, maxItems

{.... "minItems":0, "maxItems":2....}


 - 아이템 수롤 지정할 수 있다.

 - type이 array일 경우 해당 옵션으로 아이템 수를 체크할 수 있다.


+ Recent posts