Skip to content
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

feat: Dynamic agent registeration & multiple stomp topic & scheduler feature #60

Merged
merged 96 commits into from
Mar 30, 2024
Merged
Show file tree
Hide file tree
Changes from 95 commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
976c174
dev: change static css/styles.css path in html
ghkdqhrbals Mar 26, 2024
5beda3c
dev: temporary add Randomized TestResult SSE event
ghkdqhrbals Mar 26, 2024
207b0e1
Merge branch 'develop' into feature/template-info-builder
ghkdqhrbals Mar 26, 2024
2bc3f97
dev: css textarea style add
ghkdqhrbals Mar 26, 2024
38d353e
dev: json mapper method add
ghkdqhrbals Mar 26, 2024
3c31f8e
dev: CommonTestResult class name change
ghkdqhrbals Mar 26, 2024
43d1924
dev: CommonTestResult class name change
ghkdqhrbals Mar 26, 2024
d3d1b31
dev: invalid json string errorcode
ghkdqhrbals Mar 26, 2024
ac40e5f
dev: TemplateInfo getting service
ghkdqhrbals Mar 26, 2024
ce8469f
dev: util for verify accessable template
ghkdqhrbals Mar 26, 2024
471a800
dev: add all throws JsonParsing exception
ghkdqhrbals Mar 26, 2024
982fafc
dev: add prepareScript & header field
ghkdqhrbals Mar 26, 2024
0c40e81
dev: jsonMapper pre-defining
ghkdqhrbals Mar 26, 2024
21a186c
dev: pre-check invalid json body
ghkdqhrbals Mar 26, 2024
1713981
dev: headers & prepareScript entity field add
ghkdqhrbals Mar 26, 2024
7d1c553
dev: remove unused test and add exception
ghkdqhrbals Mar 26, 2024
518c834
dev: JsonProcessingException add
ghkdqhrbals Mar 26, 2024
e5cdd1b
dev: remove random method and add vuser, maxRequest, maxDuration field
ghkdqhrbals Mar 26, 2024
d3b4d31
dev: TestResult class change
ghkdqhrbals Mar 26, 2024
539ffb7
dev: pre-build empty template
ghkdqhrbals Mar 26, 2024
51461ea
dev: add front design and functional method
ghkdqhrbals Mar 26, 2024
3bed3bc
dev: http load sender with multi threads
ghkdqhrbals Mar 27, 2024
3e944c4
dev: dns resolver apple silicon dependency
ghkdqhrbals Mar 27, 2024
44f6f67
dev: change dto field
ghkdqhrbals Mar 27, 2024
3e32f33
dev: additional method and comments
ghkdqhrbals Mar 27, 2024
4a3bdde
dev: apply changed field
ghkdqhrbals Mar 27, 2024
5d42dbb
chore: apply changed field
ghkdqhrbals Mar 27, 2024
ffe9273
dev: health check endpoint
ghkdqhrbals Mar 27, 2024
ac77c95
dev: RequestSpec setter
ghkdqhrbals Mar 27, 2024
cca8073
dev: child thread with parent thread dependency setting
ghkdqhrbals Mar 27, 2024
c352c4c
dev: child thread managing method
ghkdqhrbals Mar 27, 2024
f24f812
dev: TPS, MTTFB percentile consts
ghkdqhrbals Mar 27, 2024
0a584b4
dev: TestResult scheduled & async-nonblocking http sender & emitter u…
ghkdqhrbals Mar 27, 2024
96be58e
Merge branch 'develop' into feature/template-info-builder
ghkdqhrbals Mar 27, 2024
7b036ae
test: add mockServer test
ghkdqhrbals Mar 27, 2024
2ce4f04
Merge remote-tracking branch 'origin/feature/template-info-builder' i…
ghkdqhrbals Mar 27, 2024
f67ae86
fix: java syntax error
ghkdqhrbals Mar 27, 2024
feccd35
dev: split service & controller
ghkdqhrbals Mar 27, 2024
1f2f47b
dev: pr comment merge & test remove
ghkdqhrbals Mar 27, 2024
cb30ee8
dev: test exclude setting
ghkdqhrbals Mar 27, 2024
a19caa1
dev: add jacoco perfTest within gradle
ghkdqhrbals Mar 27, 2024
439d15a
dev: sse mocking response method !
ghkdqhrbals Mar 27, 2024
2299f1d
dev: test code with sse mock response & message event
ghkdqhrbals Mar 27, 2024
dfa69e8
dev: schedulerManager duplication/shutdown test
ghkdqhrbals Mar 27, 2024
bcf877c
dev: requestHeadersSpec test
ghkdqhrbals Mar 27, 2024
f51d51b
dev: HealthCheck controller test
ghkdqhrbals Mar 27, 2024
325b14a
dev: agent information dto
ghkdqhrbals Mar 28, 2024
615fb63
dev: agent status manager setup
ghkdqhrbals Mar 28, 2024
b271eee
dev: agent status manager testing
ghkdqhrbals Mar 28, 2024
1b5a2bd
dev: agent system scheduler
ghkdqhrbals Mar 28, 2024
8a3660d
dev: test with cpu, memory, url, etc.
ghkdqhrbals Mar 28, 2024
c9f5578
dev: system scheduler constant
ghkdqhrbals Mar 28, 2024
4611553
dev: encapsulate method
ghkdqhrbals Mar 28, 2024
6b24bda
chore: remove system print
ghkdqhrbals Mar 28, 2024
cc0ef03
dev: maxRequest maxDuration validator
ghkdqhrbals Mar 28, 2024
a9a3896
chore: const test exclude
ghkdqhrbals Mar 28, 2024
3082a0c
test: sendRequest wrong url, duration null
ghkdqhrbals Mar 28, 2024
6dc6f42
test: AgentInfo endpoint
ghkdqhrbals Mar 28, 2024
95449b6
dev: eureka bm-agent discovery service
ghkdqhrbals Mar 28, 2024
56c49e6
dev: netflix eureka and actuator setup
ghkdqhrbals Mar 28, 2024
00af4ba
dev: eureka app-name change clarify
ghkdqhrbals Mar 28, 2024
9b8526d
dev: discovery current bm-agent finder scheduler
ghkdqhrbals Mar 28, 2024
37f0572
dev: exit code
ghkdqhrbals Mar 28, 2024
a136329
dev: connect bm-controller method
ghkdqhrbals Mar 28, 2024
174a7ca
chore: logging error
ghkdqhrbals Mar 28, 2024
6719c91
dev: scheduler task
ghkdqhrbals Mar 28, 2024
b23124a
dev: token provider impl. and test
ghkdqhrbals Mar 28, 2024
cb2e195
dev: header prefix
ghkdqhrbals Mar 28, 2024
90453c3
dev: regular system constant
ghkdqhrbals Mar 28, 2024
8ab500e
dev: append agentStatusManager to constructor
ghkdqhrbals Mar 28, 2024
cce9003
test: performance, initial, sender test
ghkdqhrbals Mar 28, 2024
994d22b
dev: commandLineRunner for connect to bm-controller
ghkdqhrbals Mar 28, 2024
b16858d
dev: lock performance test agent when it is running
ghkdqhrbals Mar 28, 2024
74dcb42
dev: pagination api
ghkdqhrbals Mar 28, 2024
6080608
dev: agent status READY when task is done
ghkdqhrbals Mar 28, 2024
5725d0e
chore: remove unused test
ghkdqhrbals Mar 28, 2024
348f72e
dev: reconfigure agent manager
ghkdqhrbals Mar 28, 2024
79d2428
test: restapi endpoint change and apply to it
ghkdqhrbals Mar 28, 2024
b7445e1
dev: agent listener
ghkdqhrbals Mar 28, 2024
58fc69a
dev: performance test lock
ghkdqhrbals Mar 28, 2024
0336624
dev: adjust test code
ghkdqhrbals Mar 28, 2024
89e0f44
dev: always on ready state
ghkdqhrbals Mar 28, 2024
39d6844
Merge branch 'develop' into feature/template-info-builder
ghkdqhrbals Mar 28, 2024
039e99a
dev: version setup
ghkdqhrbals Mar 28, 2024
940953d
dev: docker composing configure
ghkdqhrbals Mar 28, 2024
cb15413
Merge remote-tracking branch 'origin/feature/template-info-builder' i…
ghkdqhrbals Mar 28, 2024
4cf0cb3
chore: remove unused option
ghkdqhrbals Mar 29, 2024
23b52d3
dev: th fragment header
ghkdqhrbals Mar 29, 2024
ed03ad7
dev: th fragment showing agent status with ws
ghkdqhrbals Mar 29, 2024
55a703f
dev: scheduler for send ws events
ghkdqhrbals Mar 29, 2024
5195d48
dev: add header&agentStatus fragments
ghkdqhrbals Mar 29, 2024
51c07c8
dev: stomp connection with 3 topics
ghkdqhrbals Mar 29, 2024
d19f4ce
dev: styling agent status shower
ghkdqhrbals Mar 29, 2024
045c181
dev: clarify path variable values
ghkdqhrbals Mar 29, 2024
9e79744
dev: agent status update, emitter completion
ghkdqhrbals Mar 29, 2024
3a5d13a
chore: apply meaningful field name
ghkdqhrbals Mar 30, 2024
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
21 changes: 20 additions & 1 deletion bm-agent/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,32 @@ plugins {
}

group = 'org.benchmarker'
version = '0.0.1-SNAPSHOT'
version = '1.0.0'

def excludeJacocoTestCoverageReport = [
// bmagent
'org/benchmarker/bmagent/BmAgentApplication**',
'org/benchmarker/bmagent/sse/**',
'org/benchmarker/bmagent/consts/SystemSchedulerConst',
'org/benchmarker/bmagent/status/**',
'org/benchmarker/bmagent/initializer/**',
// 'org/benchmarker/bmagent/**',
]

java {
sourceCompatibility = '17'
}

ext {
set('springCloudVersion', "2023.0.0")
}

dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}

jacoco {
toolVersion = "0.8.8"
}
Expand All @@ -41,16 +53,23 @@ dependencies {
implementation 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
// add webflux
implementation 'org.springframework.boot:spring-boot-starter-webflux'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.boot:spring-boot-testcontainers'
testImplementation 'org.testcontainers:junit-jupiter'
testImplementation 'com.squareup.okhttp3:mockwebserver:4.9.1'

implementation "io.jsonwebtoken:jjwt-api:0.11.1"
runtimeOnly "io.jsonwebtoken:jjwt-impl:0.11.1"
runtimeOnly "io.jsonwebtoken:jjwt-jackson:0.11.1"
if (isAppleSilicon()) {
runtimeOnly("io.netty:netty-resolver-dns-native-macos:4.1.94.Final:osx-aarch_64")
}

implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'

implementation project(':bm-common')
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
package org.benchmarker.bmagent;

import org.springframework.boot.ExitCodeGenerator;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class BmAgentApplication {
@Bean
public ExitCodeGenerator exitCodeGenerator() {
return new ExitCodeGenerator() {
@Override
public int getExitCode() {
return 42;
}
};
}

public static void main(String[] args) {
System.setProperty("spring.application.name","bm-agent");
SpringApplication.run(BmAgentApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.benchmarker.bmagent.consts;

public interface HeaderConst {
String bearerPrefix = "Bearer ";
String tokenKey = "Authorization";

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@ public interface SystemSchedulerConst {
*/
Long systemSchedulerId = -100L;
String systemUsageSchedulerName = "cpu-memory-usage-update";
Integer connectControllerTimeout = 10; // seconds
Integer connectionFailedLimit = 50;


}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import jakarta.servlet.http.HttpServletRequest;
import java.util.Map;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.benchmarker.bmagent.AgentInfo;
Expand Down Expand Up @@ -42,15 +43,16 @@ public class AgentApiController {
* @param action String
* @return SseEmitter
*/
@PostMapping("/templates/{template_id}")
@PostMapping("/groups/{group_id}/templates/{template_id}")
public SseEmitter manageSSE(@PathVariable("template_id") Long templateId,
@PathVariable("group_id") String groupId,
@RequestParam("action") String action, @RequestBody TemplateInfo templateInfo) {
log.info(templateInfo.toString());
agentStatusManager.getAndUpdateStatusIfReady(
AgentStatus.TESTING).orElseThrow(() -> new RuntimeException("agent is not ready"));

if (action.equals("start")) {
return sseManageService.start(templateId, templateInfo);
agentStatusManager.getAndUpdateStatusIfReady(
AgentStatus.TESTING).orElseThrow(() -> new RuntimeException("agent is not ready"));
return sseManageService.start(templateId, groupId, templateInfo);
} else {
sseManageService.stop(templateId);
return null;
Expand All @@ -73,10 +75,12 @@ public AgentInfo getStatus() {
String scheme = request.getScheme(); // http or https
String serverName = request.getServerName();
int serverPort = request.getServerPort();
Set<Long> longs = scheduledTaskService.getStatus().keySet();

String agentServerUrl = scheme + "://" + serverName + ":" + serverPort;

return AgentInfo.builder()
.templateId(longs)
.cpuUsage(agentStatusManager.getCpuUsage())
.memoryUsage(agentStatusManager.getMemoryUsage())
.startedAt(agentStatusManager.getStartedAt())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,39 @@

import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.benchmarker.bmagent.consts.SystemSchedulerConst;
import org.benchmarker.bmagent.schedule.ScheduledTaskService;
import org.benchmarker.bmagent.status.AgentStatusManager;
import org.springframework.beans.BeansException;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;

@Component
@Profile("!test")
@Slf4j
@RequiredArgsConstructor
public class Initializer implements CommandLineRunner {
public class Initializer implements CommandLineRunner, ApplicationContextAware {

private final ScheduledTaskService scheduledTaskService;
private final AgentStatusManager agentStatusManager;
private ApplicationContext applicationContext;


@Override
public void run(String... args) throws Exception {
log.info("init");
// cpu, memory usage checker
scheduledTaskService.startChild(SystemSchedulerConst.systemSchedulerId,
SystemSchedulerConst.systemUsageSchedulerName, agentStatusManager::updateStats, 0, 1,
TimeUnit.SECONDS);
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
import java.util.stream.IntStream;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.benchmarker.bmagent.AgentStatus;
import org.benchmarker.bmagent.service.IScheduledTaskService;
import org.benchmarker.bmagent.status.AgentStatusManager;
import org.benchmarker.bmagent.util.WebClientSupport;
import org.benchmarker.bmcommon.dto.TemplateInfo;
import org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Mono;

/**
Expand All @@ -35,14 +38,17 @@ public class HttpSender {
private final ResultManagerService resultManagerService;
private final IScheduledTaskService scheduledTaskService;

private final AgentStatusManager agentStatusManager;


public HttpSender(ResultManagerService resultManagerService,
IScheduledTaskService scheduledTaskService) {
IScheduledTaskService scheduledTaskService, AgentStatusManager agentStatusManager) {
this.resultManagerService = resultManagerService;
this.scheduledTaskService = scheduledTaskService;
this.agentStatusManager = agentStatusManager;
}

private Integer defaultMaxRequestsPerUser = 100000000;
private Integer defaultMaxRequestsPerUser = Integer.MAX_VALUE;
private Integer defaultMaxDuration = 5; // 5 hours
private AtomicInteger totalRequests = new AtomicInteger(0);
private AtomicInteger totalSuccess = new AtomicInteger(0);
Expand All @@ -66,7 +72,8 @@ public HttpSender(ResultManagerService resultManagerService,
*
* @param templateInfo {@link TemplateInfo}
*/
public void sendRequests(TemplateInfo templateInfo) throws MalformedURLException {
public void sendRequests(SseEmitter sseEmitter, TemplateInfo templateInfo) throws MalformedURLException {

URL url = new URL(templateInfo.getUrl());
RequestHeadersSpec<?> req = WebClientSupport.create(templateInfo.getMethod(),
templateInfo.getUrl(),
Expand All @@ -85,16 +92,20 @@ public void sendRequests(TemplateInfo templateInfo) throws MalformedURLException
}

Duration duration = templateInfo.getMaxDuration();
log.info("Now send multiple HTTP request to target server");
log.info(templateInfo.toString());

// Future setup
futures = IntStream.range(0, templateInfo.getVuser())
.mapToObj(i -> CompletableFuture.runAsync(() -> {
long startTime = System.currentTimeMillis(); // 시작 시간 기록
long endTime = startTime + duration.toMillis();

for (int j = 0; j < templateInfo.getMaxRequest(); j++) {
// 만약 running 이 아니거나 시간이 끝났다면,
if (!isRunning || System.currentTimeMillis() > endTime) {
return;
agentStatusManager.updateAgentStatus(AgentStatus.READY);
break;
}
long requestStartTime = System.currentTimeMillis(); // 요청 시작 시간 기록
req.exchangeToMono(resp -> {
Expand Down Expand Up @@ -192,6 +203,7 @@ public Map<Double, Double> calculateMttfbPercentile(List<Double> percentile) {
* downstream 에서만 제거 가능. 외부에서는 cancel 불가능...
*/
public void cancelRequests() {
log.info("cancel requests");
isRunning = false;

}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.benchmarker.bmagent.security;


import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import java.util.Date;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
* {@link JwtTokenProvider} class is used to create Json Web Token.
*/
@Slf4j
@Component
@Setter
public class JwtTokenProvider {

/**
* Access token's expiration time
*/
public static String expirationTime;

/**
* Refresh token's expiration time
*/
public static String refreshExpirationTime;

/**
* Secret key for signing the token
*/
public static String secret;

@Value("${token.expiration_time}")
private void setExpirationTime(String expirationTime) {
JwtTokenProvider.expirationTime = expirationTime;
}

@Value("${token.refresh_expiration_time}")
private void setRefreshExpirationTime(String refreshExpirationTime) {
JwtTokenProvider.refreshExpirationTime = refreshExpirationTime;
}

@Value("${token.secret}")
private void setSecret(String secret) {
JwtTokenProvider.secret = secret;
}


/**
* Create Json Web Token with user's username and authorities
*
* <p> Here, this method generate accessToken </p>
* <p> JWT's payload will looks like below</p>
* <blockquote><pre>
* {
* "sub": "agent"
* }
* </pre></blockquote>
*
* @return Json-web-token
*/
public static String createAccessToken() {
Claims claims = Jwts.claims().setSubject("agent");

Long expirationTimeLong = Long.parseLong(expirationTime);
final Date createdDate = new Date();
final Date expirationDate = new Date(createdDate.getTime() + expirationTimeLong);
return Jwts.builder()
.setClaims(claims)
.setSubject("agent")
.setIssuedAt(createdDate)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public interface ISseManageService extends SseManageConsts {
* @param templateInfo TemplateInfo
* @return SseEmitter
*/
SseEmitter start(Long id, TemplateInfo templateInfo);
SseEmitter start(Long id, String groupId, TemplateInfo templateInfo);

/**
* Stop the SSE emitter for the given id
Expand Down
Loading
Loading