or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application-management.mdartifact-management.mdconfiguration.mddata-operations.mddataset-operations.mdindex.mdmetrics-monitoring.mdprogram-control.mdschedule-management.mdsecurity-administration.mdservice-management.md

service-management.mddocs/

0

# Service Management

1

2

The ServiceClient provides comprehensive user service interactions including endpoint discovery, availability checking, routing configuration, and direct service method calls. Services are HTTP-based programs that expose RESTful endpoints.

3

4

## ServiceClient

5

6

```java { .api }

7

public class ServiceClient {

8

// Constructors

9

public ServiceClient(ClientConfig config);

10

public ServiceClient(ClientConfig config, RESTClient restClient);

11

12

// Service information methods

13

public ServiceSpecification get(ProgramId service);

14

public List<ServiceHttpEndpoint> getEndpoints(ServiceId service);

15

public void checkAvailability(ServiceId service);

16

public URL getVersionedServiceURL(ServiceId service);

17

public URL getServiceURL(ServiceId service);

18

19

// Route configuration methods

20

public Map<String, Integer> getRouteConfig(ServiceId serviceId);

21

public void storeRouteConfig(ServiceId serviceId, Map<String, Integer> routeConfig);

22

public void deleteRouteConfig(ServiceId serviceId);

23

24

// Service call methods

25

public HttpResponse callServiceMethod(ServiceId serviceId, String methodPath);

26

}

27

```

28

29

## Service Types and Information

30

31

```java { .api }

32

public class ServiceSpecification {

33

public String getName();

34

public String getClassName();

35

public String getDescription();

36

public Map<String, HttpServiceHandlerSpecification> getHandlers();

37

public ResourceSpecification getResources();

38

}

39

40

public class ServiceHttpEndpoint {

41

public String getMethod();

42

public String getPath();

43

}

44

45

public class ServiceId {

46

public static ServiceId of(ApplicationId application, String service);

47

public ApplicationId getApplication();

48

public String getService();

49

}

50

51

public class HttpResponse {

52

public int getResponseCode();

53

public Map<String, List<String>> getHeaders();

54

public String getResponseMessage();

55

public byte[] getResponseBody();

56

public String getResponseBodyAsString();

57

}

58

```

59

60

## Service Discovery and Information

61

62

### Service Specification

63

64

```java

65

// Get service specification

66

ApplicationId appId = ApplicationId.of(namespace, "web-analytics", "1.0.0");

67

ProgramId serviceProgram = ProgramId.of(appId, ProgramType.SERVICE, "analytics-service");

68

ServiceSpecification spec = serviceClient.get(serviceProgram);

69

70

System.out.println("Service: " + spec.getName());

71

System.out.println("Class: " + spec.getClassName());

72

System.out.println("Description: " + spec.getDescription());

73

74

// Get handlers information

75

Map<String, HttpServiceHandlerSpecification> handlers = spec.getHandlers();

76

for (Map.Entry<String, HttpServiceHandlerSpecification> entry : handlers.entrySet()) {

77

System.out.println("Handler: " + entry.getKey());

78

HttpServiceHandlerSpecification handler = entry.getValue();

79

System.out.println(" Class: " + handler.getClassName());

80

System.out.println(" Endpoints: " + handler.getEndpoints().size());

81

}

82

83

// Get resource requirements

84

ResourceSpecification resources = spec.getResources();

85

System.out.println("Memory: " + resources.getMemoryMB() + " MB");

86

System.out.println("VCores: " + resources.getVirtualCores());

87

```

88

89

### Endpoint Discovery

90

91

```java

92

// Get all endpoints for a service

93

ServiceId serviceId = ServiceId.of(appId, "analytics-service");

94

List<ServiceHttpEndpoint> endpoints = serviceClient.getEndpoints(serviceId);

95

96

System.out.println("Service endpoints:");

97

for (ServiceHttpEndpoint endpoint : endpoints) {

98

System.out.println(" " + endpoint.getMethod() + " " + endpoint.getPath());

99

}

100

101

// Common endpoint patterns

102

for (ServiceHttpEndpoint endpoint : endpoints) {

103

String method = endpoint.getMethod();

104

String path = endpoint.getPath();

105

106

if ("GET".equals(method) && path.contains("/status")) {

107

System.out.println("Health check endpoint: " + method + " " + path);

108

} else if ("POST".equals(method)) {

109

System.out.println("Data submission endpoint: " + method + " " + path);

110

} else if ("GET".equals(method) && path.contains("/metrics")) {

111

System.out.println("Metrics endpoint: " + method + " " + path);

112

}

113

}

114

```

115

116

### Service Availability

117

118

```java

119

// Check if service is available

120

try {

121

serviceClient.checkAvailability(serviceId);

122

System.out.println("Service is available: " + serviceId.getService());

123

} catch (ServiceUnavailableException e) {

124

System.err.println("Service unavailable: " + serviceId.getService());

125

} catch (ServiceNotFoundException e) {

126

System.err.println("Service not found: " + serviceId.getService());

127

}

128

129

// Wait for service availability

130

public void waitForServiceAvailability(ServiceId serviceId, int maxAttempts, long delayMs) {

131

for (int i = 0; i < maxAttempts; i++) {

132

try {

133

serviceClient.checkAvailability(serviceId);

134

System.out.println("Service is now available: " + serviceId.getService());

135

return;

136

} catch (ServiceUnavailableException e) {

137

if (i == maxAttempts - 1) {

138

throw new RuntimeException("Service did not become available after " + maxAttempts + " attempts");

139

}

140

System.out.println("Service not available, attempt " + (i + 1) + "/" + maxAttempts);

141

try {

142

Thread.sleep(delayMs);

143

} catch (InterruptedException ie) {

144

Thread.currentThread().interrupt();

145

throw new RuntimeException("Interrupted while waiting for service", ie);

146

}

147

}

148

}

149

}

150

```

151

152

## Service URL Management

153

154

### URL Generation

155

156

```java

157

// Get service URLs

158

URL versionedUrl = serviceClient.getVersionedServiceURL(serviceId);

159

URL unversionedUrl = serviceClient.getServiceURL(serviceId);

160

161

System.out.println("Versioned URL: " + versionedUrl);

162

System.out.println("Unversioned URL: " + unversionedUrl);

163

164

// Build endpoint URLs

165

String baseUrl = unversionedUrl.toString();

166

for (ServiceHttpEndpoint endpoint : endpoints) {

167

String endpointUrl = baseUrl + endpoint.getPath();

168

System.out.println(endpoint.getMethod() + " -> " + endpointUrl);

169

}

170

```

171

172

### Dynamic URL Construction

173

174

```java

175

// Build URLs for different environments

176

public class ServiceURLBuilder {

177

private final ServiceClient serviceClient;

178

179

public ServiceURLBuilder(ServiceClient serviceClient) {

180

this.serviceClient = serviceClient;

181

}

182

183

public String buildEndpointURL(ServiceId serviceId, String path, boolean versioned) {

184

try {

185

URL baseUrl = versioned ?

186

serviceClient.getVersionedServiceURL(serviceId) :

187

serviceClient.getServiceURL(serviceId);

188

189

return baseUrl.toString() + (path.startsWith("/") ? path : "/" + path);

190

} catch (Exception e) {

191

throw new RuntimeException("Error building service URL", e);

192

}

193

}

194

195

public String buildParameterizedURL(ServiceId serviceId, String pathTemplate, Object... params) {

196

String path = String.format(pathTemplate, params);

197

return buildEndpointURL(serviceId, path, false);

198

}

199

}

200

201

// Usage

202

ServiceURLBuilder urlBuilder = new ServiceURLBuilder(serviceClient);

203

String userUrl = urlBuilder.buildParameterizedURL(serviceId, "/users/%s", "user123");

204

String metricsUrl = urlBuilder.buildEndpointURL(serviceId, "/metrics", false);

205

```

206

207

## Route Configuration

208

209

### Traffic Routing

210

211

```java

212

// Get current route configuration

213

Map<String, Integer> currentRoutes = serviceClient.getRouteConfig(serviceId);

214

System.out.println("Current routes: " + currentRoutes);

215

216

// Configure traffic routing between service versions

217

Map<String, Integer> routeConfig = Map.of(

218

"v1.0.0", 80, // 80% traffic to v1.0.0

219

"v1.1.0", 20 // 20% traffic to v1.1.0 (canary deployment)

220

);

221

222

serviceClient.storeRouteConfig(serviceId, routeConfig);

223

System.out.println("Updated route configuration for gradual rollout");

224

225

// Blue-green deployment routing

226

Map<String, Integer> blueGreenRoutes = Map.of(

227

"blue", 0, // Old version (no traffic)

228

"green", 100 // New version (all traffic)

229

);

230

serviceClient.storeRouteConfig(serviceId, blueGreenRoutes);

231

```

232

233

### Advanced Routing Strategies

234

235

```java

236

// Gradual traffic migration

237

public void performGradualMigration(ServiceId serviceId, String oldVersion, String newVersion) {

238

int[] trafficSplits = {90, 80, 60, 40, 20, 0}; // Gradual reduction of old version traffic

239

240

for (int oldTraffic : trafficSplits) {

241

int newTraffic = 100 - oldTraffic;

242

243

Map<String, Integer> routes = Map.of(

244

oldVersion, oldTraffic,

245

newVersion, newTraffic

246

);

247

248

try {

249

serviceClient.storeRouteConfig(serviceId, routes);

250

System.out.println("Route config: " + oldVersion + "=" + oldTraffic + "%, " +

251

newVersion + "=" + newTraffic + "%");

252

253

// Wait and monitor before next step

254

Thread.sleep(300000); // 5 minutes

255

256

// Check service health before continuing

257

serviceClient.checkAvailability(serviceId);

258

259

} catch (Exception e) {

260

System.err.println("Error during migration step: " + e.getMessage());

261

// Rollback to previous configuration

262

Map<String, Integer> rollbackRoutes = Map.of(oldVersion, 100);

263

serviceClient.storeRouteConfig(serviceId, rollbackRoutes);

264

throw new RuntimeException("Migration failed, rolled back", e);

265

}

266

}

267

268

System.out.println("Migration completed successfully");

269

}

270

271

// Remove route configuration (default routing)

272

serviceClient.deleteRouteConfig(serviceId);

273

System.out.println("Route configuration removed, using default routing");

274

```

275

276

## Service Method Calls

277

278

### Direct Service Calls

279

280

```java

281

// Make direct calls to service methods

282

try {

283

// GET request

284

HttpResponse response = serviceClient.callServiceMethod(serviceId, "/status");

285

System.out.println("Status response: " + response.getResponseCode());

286

System.out.println("Body: " + response.getResponseBodyAsString());

287

288

// Check response headers

289

Map<String, List<String>> headers = response.getHeaders();

290

if (headers.containsKey("Content-Type")) {

291

System.out.println("Content-Type: " + headers.get("Content-Type").get(0));

292

}

293

294

} catch (ServiceUnavailableException e) {

295

System.err.println("Service call failed - service unavailable");

296

} catch (IOException e) {

297

System.err.println("Network error during service call: " + e.getMessage());

298

}

299

```

300

301

### Advanced HTTP Client Usage

302

303

```java

304

// Service interaction with custom HTTP client

305

public class ServiceInteractor {

306

private final ServiceClient serviceClient;

307

private final ServiceId serviceId;

308

309

public ServiceInteractor(ServiceClient serviceClient, ServiceId serviceId) {

310

this.serviceClient = serviceClient;

311

this.serviceId = serviceId;

312

}

313

314

public String getServiceStatus() {

315

try {

316

HttpResponse response = serviceClient.callServiceMethod(serviceId, "/status");

317

if (response.getResponseCode() == 200) {

318

return response.getResponseBodyAsString();

319

} else {

320

throw new RuntimeException("Service status check failed: " + response.getResponseCode());

321

}

322

} catch (Exception e) {

323

throw new RuntimeException("Error checking service status", e);

324

}

325

}

326

327

public Map<String, Object> getServiceMetrics() {

328

try {

329

HttpResponse response = serviceClient.callServiceMethod(serviceId, "/metrics");

330

if (response.getResponseCode() == 200) {

331

String jsonResponse = response.getResponseBodyAsString();

332

// Parse JSON response (using your preferred JSON library)

333

return parseJsonResponse(jsonResponse);

334

} else {

335

throw new RuntimeException("Metrics retrieval failed: " + response.getResponseCode());

336

}

337

} catch (Exception e) {

338

throw new RuntimeException("Error retrieving service metrics", e);

339

}

340

}

341

342

public boolean isHealthy() {

343

try {

344

serviceClient.checkAvailability(serviceId);

345

HttpResponse healthResponse = serviceClient.callServiceMethod(serviceId, "/health");

346

return healthResponse.getResponseCode() == 200;

347

} catch (Exception e) {

348

return false;

349

}

350

}

351

352

private Map<String, Object> parseJsonResponse(String json) {

353

// Implement JSON parsing using your preferred library (Jackson, Gson, etc.)

354

// This is a placeholder implementation

355

return Map.of("status", "parsed");

356

}

357

}

358

```

359

360

## Service Health Monitoring

361

362

### Health Check Implementation

363

364

```java

365

// Comprehensive service health monitoring

366

public class ServiceHealthMonitor {

367

private final ServiceClient serviceClient;

368

private final ServiceId serviceId;

369

370

public ServiceHealthMonitor(ServiceClient serviceClient, ServiceId serviceId) {

371

this.serviceClient = serviceClient;

372

this.serviceId = serviceId;

373

}

374

375

public ServiceHealthStatus checkHealth() {

376

ServiceHealthStatus.Builder statusBuilder = ServiceHealthStatus.builder()

377

.serviceId(serviceId)

378

.timestamp(System.currentTimeMillis());

379

380

try {

381

// Check basic availability

382

serviceClient.checkAvailability(serviceId);

383

statusBuilder.available(true);

384

385

// Check endpoints

386

List<ServiceHttpEndpoint> endpoints = serviceClient.getEndpoints(serviceId);

387

statusBuilder.endpointCount(endpoints.size());

388

389

// Test health endpoint if available

390

for (ServiceHttpEndpoint endpoint : endpoints) {

391

if ("GET".equals(endpoint.getMethod()) &&

392

(endpoint.getPath().contains("/health") || endpoint.getPath().contains("/status"))) {

393

394

HttpResponse response = serviceClient.callServiceMethod(serviceId, endpoint.getPath());

395

statusBuilder.healthEndpointStatus(response.getResponseCode());

396

statusBuilder.healthEndpointResponse(response.getResponseBodyAsString());

397

break;

398

}

399

}

400

401

// Check route configuration

402

Map<String, Integer> routes = serviceClient.getRouteConfig(serviceId);

403

statusBuilder.routeConfiguration(routes);

404

405

statusBuilder.healthy(true);

406

407

} catch (ServiceNotFoundException e) {

408

statusBuilder.available(false).healthy(false).error("Service not found");

409

} catch (ServiceUnavailableException e) {

410

statusBuilder.available(false).healthy(false).error("Service unavailable");

411

} catch (Exception e) {

412

statusBuilder.available(false).healthy(false).error("Error: " + e.getMessage());

413

}

414

415

return statusBuilder.build();

416

}

417

418

public void monitorContinuously(long intervalMs, HealthStatusCallback callback) {

419

Thread monitorThread = new Thread(() -> {

420

while (!Thread.currentThread().isInterrupted()) {

421

try {

422

ServiceHealthStatus status = checkHealth();

423

callback.onHealthStatus(status);

424

Thread.sleep(intervalMs);

425

} catch (InterruptedException e) {

426

Thread.currentThread().interrupt();

427

break;

428

} catch (Exception e) {

429

callback.onError(e);

430

}

431

}

432

});

433

434

monitorThread.setDaemon(true);

435

monitorThread.start();

436

}

437

438

@FunctionalInterface

439

public interface HealthStatusCallback {

440

void onHealthStatus(ServiceHealthStatus status);

441

442

default void onError(Exception e) {

443

System.err.println("Health monitoring error: " + e.getMessage());

444

}

445

}

446

}

447

448

// Health status data class

449

public class ServiceHealthStatus {

450

private final ServiceId serviceId;

451

private final long timestamp;

452

private final boolean available;

453

private final boolean healthy;

454

private final int endpointCount;

455

private final Integer healthEndpointStatus;

456

private final String healthEndpointResponse;

457

private final Map<String, Integer> routeConfiguration;

458

private final String error;

459

460

// Constructor, getters, and builder implementation

461

public static Builder builder() {

462

return new Builder();

463

}

464

465

public static class Builder {

466

// Builder implementation

467

}

468

}

469

```

470

471

## Error Handling

472

473

Service management operations may throw these exceptions:

474

475

- **ServiceNotFoundException**: Service does not exist

476

- **ServiceUnavailableException**: Service is not currently available

477

- **ServiceNotRunningException**: Service exists but is not running

478

- **RouteConfigurationException**: Invalid route configuration

479

- **UnauthenticatedException**: Authentication required

480

- **UnauthorizedException**: Insufficient permissions

481

482

```java

483

try {

484

ServiceSpecification spec = serviceClient.get(serviceProgram);

485

System.out.println("Service specification retrieved");

486

} catch (ServiceNotFoundException e) {

487

System.err.println("Service not found: " + serviceId.getService());

488

} catch (UnauthorizedException e) {

489

System.err.println("No permission to access service: " + e.getMessage());

490

} catch (IOException e) {

491

System.err.println("Network error: " + e.getMessage());

492

}

493

```

494

495

## Best Practices

496

497

1. **Health Monitoring**: Implement continuous health monitoring for services

498

2. **Route Management**: Use route configuration for gradual deployments

499

3. **Error Handling**: Implement proper retry logic and circuit breakers

500

4. **URL Management**: Use versioned URLs for backward compatibility

501

5. **Performance**: Monitor service response times and throughput

502

6. **Security**: Ensure proper authentication and authorization for service calls

503

504

```java

505

// Good: Comprehensive service management with error handling and monitoring

506

public class ServiceManager {

507

private final ServiceClient serviceClient;

508

private final ServiceId serviceId;

509

private final ServiceHealthMonitor healthMonitor;

510

511

public ServiceManager(ServiceClient serviceClient, ServiceId serviceId) {

512

this.serviceClient = serviceClient;

513

this.serviceId = serviceId;

514

this.healthMonitor = new ServiceHealthMonitor(serviceClient, serviceId);

515

}

516

517

public void deployWithHealthCheck(Map<String, Integer> routeConfig) {

518

try {

519

// Store new route configuration

520

serviceClient.storeRouteConfig(serviceId, routeConfig);

521

522

// Wait for deployment to stabilize

523

Thread.sleep(30000); // 30 seconds

524

525

// Verify service health

526

ServiceHealthStatus status = healthMonitor.checkHealth();

527

if (!status.isHealthy()) {

528

// Rollback on failure

529

System.err.println("Service unhealthy after deployment, rolling back");

530

serviceClient.deleteRouteConfig(serviceId); // Use default routing

531

throw new RuntimeException("Deployment failed health check");

532

}

533

534

System.out.println("Deployment successful and service is healthy");

535

536

} catch (Exception e) {

537

System.err.println("Deployment failed: " + e.getMessage());

538

throw new RuntimeException("Service deployment failed", e);

539

}

540

}

541

542

public String callServiceSafely(String methodPath, int maxRetries) {

543

Exception lastException = null;

544

545

for (int i = 0; i < maxRetries; i++) {

546

try {

547

serviceClient.checkAvailability(serviceId);

548

HttpResponse response = serviceClient.callServiceMethod(serviceId, methodPath);

549

550

if (response.getResponseCode() == 200) {

551

return response.getResponseBodyAsString();

552

} else if (response.getResponseCode() >= 500) {

553

// Server error - retry

554

Thread.sleep(1000 * (i + 1)); // Exponential backoff

555

continue;

556

} else {

557

// Client error - don't retry

558

throw new RuntimeException("Service call failed: " + response.getResponseCode());

559

}

560

561

} catch (Exception e) {

562

lastException = e;

563

if (i < maxRetries - 1) {

564

System.out.println("Service call failed, retrying... (" + (i + 1) + "/" + maxRetries + ")");

565

try {

566

Thread.sleep(1000 * (i + 1));

567

} catch (InterruptedException ie) {

568

Thread.currentThread().interrupt();

569

throw new RuntimeException("Interrupted during retry", ie);

570

}

571

}

572

}

573

}

574

575

throw new RuntimeException("Service call failed after " + maxRetries + " attempts", lastException);

576

}

577

}

578

```