215 lines
6.3 KiB
Zig
215 lines
6.3 KiB
Zig
const std = @import("std");
|
|
|
|
const testing = std.testing;
|
|
const expect = testing.expect;
|
|
|
|
const HttpService = @import("http_service.zig").HttpService;
|
|
|
|
const s = @import("service.zig");
|
|
const ServiceTicket = s.ServiceTicket;
|
|
|
|
const ServicePoolError = error{ FullPoll, NoServiceAvailable };
|
|
|
|
pub const ServicePool = struct {
|
|
services: [10]*HttpService = undefined,
|
|
services_len: usize = 0,
|
|
|
|
pub fn add(self: *ServicePool, service: *HttpService) ServicePoolError!void {
|
|
if (service.connections.len == 0) {
|
|
return;
|
|
}
|
|
|
|
if (self.services_len == self.services.len) {
|
|
return ServicePoolError.FullPoll;
|
|
}
|
|
|
|
self.services[self.services_len] = service;
|
|
self.services_len += 1;
|
|
}
|
|
|
|
pub fn dive(self: *ServicePool, message: []const u8) ServicePoolError!*ServiceTicket {
|
|
var skip: [10]bool = .{false} ** 10;
|
|
|
|
for (0..self.services_len) |_| {
|
|
var best_service = self.findBestService(&skip);
|
|
|
|
if (best_service == null) {
|
|
return error.NoServiceAvailable;
|
|
}
|
|
|
|
const ticket = best_service.?.queue(message);
|
|
|
|
if (ticket == null) {
|
|
continue;
|
|
}
|
|
|
|
return ticket.?;
|
|
}
|
|
|
|
return error.NoServiceAvailable;
|
|
}
|
|
|
|
fn findBestService(self: *ServicePool, skip: []bool) ?*HttpService {
|
|
var first_service_available_i: ?usize = null;
|
|
var best_perfomance_i: ?usize = null;
|
|
|
|
for (0..self.services_len) |i| {
|
|
if (skip[i]) {
|
|
continue;
|
|
}
|
|
|
|
const service = self.services[i];
|
|
|
|
if (service.health == .unavailable or service.capacity >= 90) {
|
|
continue;
|
|
}
|
|
|
|
if (first_service_available_i == null) {
|
|
first_service_available_i = i;
|
|
}
|
|
|
|
if (best_perfomance_i == null or self.services[best_perfomance_i.?].response_time > service.response_time) {
|
|
best_perfomance_i = i;
|
|
}
|
|
}
|
|
|
|
if (best_perfomance_i != null) {
|
|
skip[best_perfomance_i.?] = true;
|
|
return self.services[best_perfomance_i.?];
|
|
}
|
|
|
|
if (first_service_available_i != null) {
|
|
skip[first_service_available_i.?] = true;
|
|
return self.services[first_service_available_i.?];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
};
|
|
|
|
test "expect error FullPoll if more then 10 service is added" {
|
|
var service_pool = ServicePool{};
|
|
|
|
for (0..10) |_| {
|
|
var service = try HttpService.init(1, "default", "one.one.one.one", 53, 40, testing.allocator);
|
|
defer service.deinit();
|
|
try service_pool.add(&service);
|
|
}
|
|
|
|
var service = try HttpService.init(1, "default", "one.one.one.one", 53, 40, testing.allocator);
|
|
defer service.deinit();
|
|
|
|
service_pool.add(&service) catch |err| {
|
|
try expect(err == ServicePoolError.FullPoll);
|
|
return;
|
|
};
|
|
|
|
try expect(false);
|
|
}
|
|
|
|
test "expect NoServiceAvailable if no service has been add" {
|
|
var service_pool = ServicePool{};
|
|
|
|
_ = service_pool.dive("test") catch |err| {
|
|
try expect(err == ServicePoolError.NoServiceAvailable);
|
|
return;
|
|
};
|
|
|
|
try expect(false);
|
|
}
|
|
|
|
test "expect if NoServiceAvailable all sevice are unavailable" {
|
|
var service_pool = ServicePool{};
|
|
|
|
for (0..10) |_| {
|
|
var service = try HttpService.init(1, "default", "one.one.one.one", 53, 40, testing.allocator);
|
|
service.health = .unavailable;
|
|
defer service.deinit();
|
|
try service_pool.add(&service);
|
|
}
|
|
|
|
var service = try HttpService.init(2, "default", "one.one.one.one", 53, 40, testing.allocator);
|
|
defer service.deinit();
|
|
|
|
service_pool.add(&service) catch |err| {
|
|
try expect(err == ServicePoolError.FullPoll);
|
|
return;
|
|
};
|
|
|
|
try expect(false);
|
|
}
|
|
|
|
test "expect choice service with best perfomance" {
|
|
var service_pool = ServicePool{};
|
|
|
|
var service1 = try HttpService.init(1, "default", "one.one.one.one", 53, 40, testing.allocator);
|
|
service1.health = .available;
|
|
service1.response_time = 100;
|
|
defer service1.deinit();
|
|
try service_pool.add(&service1);
|
|
|
|
var service2 = try HttpService.init(2, "fallback", "one.one.one.one", 53, 40, testing.allocator);
|
|
service2.health = .available;
|
|
service2.response_time = 10;
|
|
defer service2.deinit();
|
|
try service_pool.add(&service2);
|
|
|
|
var skip: [10]bool = .{false} ** 10;
|
|
const res = service_pool.findBestService(&skip);
|
|
|
|
try expect(res.? == &service2);
|
|
try expect(skip[1]);
|
|
}
|
|
|
|
test "expect choice service first service available if all has the same perfomance" {
|
|
var service_pool = ServicePool{};
|
|
|
|
var service1 = try HttpService.init(1, "default", "one.one.one.one", 53, 40, testing.allocator);
|
|
service1.health = .available;
|
|
service1.response_time = 10;
|
|
defer service1.deinit();
|
|
try service_pool.add(&service1);
|
|
|
|
var service2 = try HttpService.init(2, "fallback", "one.one.one.one", 53, 40, testing.allocator);
|
|
service2.health = .available;
|
|
service2.response_time = 10;
|
|
defer service2.deinit();
|
|
try service_pool.add(&service2);
|
|
|
|
var skip: [10]bool = .{false} ** 10;
|
|
const res = service_pool.findBestService(&skip);
|
|
|
|
try expect(res.? == &service1);
|
|
try expect(skip[0]);
|
|
}
|
|
|
|
test "expect choice service with overloaded" {
|
|
var service_pool = ServicePool{};
|
|
|
|
var service1 = try HttpService.init(1, "default", "one.one.one.one", 53, 40, testing.allocator);
|
|
service1.health = .available;
|
|
service1.response_time = 10;
|
|
service1.capacity = 90;
|
|
defer service1.deinit();
|
|
try service_pool.add(&service1);
|
|
|
|
var service2 = try HttpService.init(2, "fallback", "one.one.one.one", 53, 40, testing.allocator);
|
|
service2.health = .available;
|
|
service2.response_time = 10;
|
|
service2.capacity = 100;
|
|
defer service2.deinit();
|
|
try service_pool.add(&service2);
|
|
|
|
var service3 = try HttpService.init(3, "fallback_fallback", "one.one.one.one", 53, 40, testing.allocator);
|
|
service3.health = .available;
|
|
service3.response_time = 10;
|
|
service3.capacity = 50;
|
|
defer service3.deinit();
|
|
try service_pool.add(&service3);
|
|
|
|
var skip: [10]bool = .{false} ** 10;
|
|
const res = service_pool.findBestService(&skip);
|
|
|
|
try expect(res.? == &service3);
|
|
try expect(skip[2]);
|
|
}
|