guidewire-cost-tuning
Optimize Guidewire Cloud costs including license management, resource allocation, API usage optimization, and cloud infrastructure right-sizing. Trigger with phrases like "guidewire costs", "reduce spending", "license optimization", "cloud costs", "resource optimization guidewire". allowed-tools: Read, Write, Edit, Bash(curl:*), Grep version: 1.0.0 license: MIT author: Jeremy Longshore <jeremy@intentsolutions.io>
Allowed Tools
No tools specified
Provided by Plugin
guidewire-pack
Claude Code skill pack for Guidewire InsuranceSuite (24 skills)
Installation
This skill is included in the guidewire-pack plugin:
/plugin install guidewire-pack@claude-code-plugins-plus
Click to copy
Instructions
# Guidewire Cost Tuning
## Overview
Optimize Guidewire Cloud Platform costs through license management, API efficiency, resource right-sizing, and operational best practices.
## Prerequisites
- Access to Guidewire Cloud Console billing
- Understanding of Guidewire licensing model
- Access to usage metrics and reports
## Cost Components
| Component | Billing Model | Optimization Focus |
|-----------|---------------|-------------------|
| Licensing | Per user/policy | User management, policy counts |
| API Calls | Per call/volume | Request optimization, caching |
| Storage | Per GB | Data retention, archiving |
| Compute | Per instance-hour | Right-sizing, auto-scaling |
| Data Transfer | Per GB | Efficient payloads, compression |
## Instructions
### Step 1: Analyze Current Usage
```typescript
// Cost analysis utilities
interface UsageMetrics {
period: string;
apiCalls: number;
activeUsers: number;
storageGB: number;
computeHours: number;
dataTransferGB: number;
}
interface CostBreakdown {
licensing: number;
apiCalls: number;
storage: number;
compute: number;
dataTransfer: number;
total: number;
}
class CostAnalyzer {
async getUsageReport(startDate: Date, endDate: Date): Promise {
const token = await this.getToken();
const response = await fetch(
`${this.gccUrl}/api/v1/usage?start=${startDate.toISOString()}&end=${endDate.toISOString()}`,
{
headers: { 'Authorization': `Bearer ${token}` }
}
);
return response.json();
}
async getCostBreakdown(startDate: Date, endDate: Date): Promise {
const usage = await this.getUsageReport(startDate, endDate);
return {
licensing: this.calculateLicensingCost(usage),
apiCalls: this.calculateApiCost(usage),
storage: this.calculateStorageCost(usage),
compute: this.calculateComputeCost(usage),
dataTransfer: this.calculateTransferCost(usage),
total: 0 // Sum calculated below
};
}
identifyOptimizations(usage: UsageMetrics): Optimization[] {
const optimizations: Optimization[] = [];
// Check for inactive users
if (usage.activeUsers < usage.totalLicensedUsers * 0.7) {
optimizations.push({
type: 'licensing',
description: 'Reduce unused user licenses',
potentialSavings: (usage.totalLicensedUsers - usage.activeUsers) * this.perUserCost,
priority: 'high'
});
}
// Check for high API volume
if (usage.apiCalls > usage.expectedApiCalls * 1.5) {
optimizations.push({
type: 'api',
description: 'Implement API response caching',
potentialSavings: usage.apiCalls * 0.3 * this.perApiCallCost,
priority: 'medium'
});
}
// Check for storage growth
if (usage.storageGrowthRate > 0.1) { // 10% monthly growth
optimizations.push({
type: 'storage',
description: 'Implement data archiving policy',
potentialSavings: usage.storageGB * 0.2 * this.perGBCost,
priority: 'medium'
});
}
return optimizations;
}
}
```
### Step 2: License Optimization
```typescript
// User license management
interface UserActivity {
userId: string;
lastLogin: Date;
loginCount30Days: number;
role: string;
department: string;
}
class LicenseOptimizer {
async analyzeUserActivity(): Promise {
const users = await this.getUserActivity();
const inactive30Days = users.filter(u =>
daysSince(u.lastLogin) > 30 && u.loginCount30Days === 0
);
const inactive90Days = users.filter(u =>
daysSince(u.lastLogin) > 90
);
const lowActivity = users.filter(u =>
u.loginCount30Days < 5 && u.loginCount30Days > 0
);
return {
totalUsers: users.length,
inactive30Days: inactive30Days.length,
inactive90Days: inactive90Days.length,
lowActivity: lowActivity.length,
recommendations: this.generateRecommendations(inactive30Days, inactive90Days, lowActivity)
};
}
generateRecommendations(
inactive30: UserActivity[],
inactive90: UserActivity[],
lowActivity: UserActivity[]
): Recommendation[] {
const recommendations: Recommendation[] = [];
// Deactivate 90-day inactive users
if (inactive90.length > 0) {
recommendations.push({
action: 'DEACTIVATE_USERS',
users: inactive90.map(u => u.userId),
reason: 'No activity for 90+ days',
estimatedSavings: inactive90.length * this.userLicenseCost
});
}
// Review 30-day inactive users
if (inactive30.length > 0) {
recommendations.push({
action: 'REVIEW_USERS',
users: inactive30.map(u => u.userId),
reason: 'No activity for 30+ days',
estimatedSavings: inactive30.length * 0.5 * this.userLicenseCost
});
}
// Consider read-only licenses for low activity
if (lowActivity.length > 0) {
recommendations.push({
action: 'DOWNGRADE_LICENSE',
users: lowActivity.map(u => u.userId),
reason: 'Low activity - consider read-only license',
estimatedSavings: lowActivity.length * 0.6 * this.userLicenseCost
});
}
return recommendations;
}
}
```
### Step 3: API Cost Optimization
```typescript
// API usage optimization
class ApiCostOptimizer {
private callCounts: Map = new Map();
// Track API call patterns
trackCall(endpoint: string, responseSize: number): void {
const key = endpoint.replace(/\/[a-f0-9-]{36}/g, '/{id}'); // Normalize IDs
this.callCounts.set(key, (this.callCounts.get(key) || 0) + 1);
}
// Identify optimization opportunities
analyzePatterns(): ApiOptimization[] {
const optimizations: ApiOptimization[] = [];
// Find frequently called endpoints
const topEndpoints = Array.from(this.callCounts.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 10);
topEndpoints.forEach(([endpoint, count]) => {
// Suggest caching for read-heavy endpoints
if (endpoint.includes('GET') && count > 1000) {
optimizations.push({
type: 'CACHE',
endpoint,
callCount: count,
suggestion: 'Implement response caching',
potentialReduction: 0.7
});
}
// Suggest batching for related calls
if (endpoint.includes('/accounts/') && count > 500) {
optimizations.push({
type: 'BATCH',
endpoint,
callCount: count,
suggestion: 'Use includes parameter to reduce calls',
potentialReduction: 0.5
});
}
});
return optimizations;
}
}
// Implement efficient API patterns
class EfficientApiClient {
private cache: LRUCache;
private batchQueue: Map>;
// Cache responses for repeated requests
async getCached(
cacheKey: string,
fetcher: () => Promise,
ttlMs: number = 60000
): Promise {
const cached = this.cache.get(cacheKey);
if (cached) {
return cached;
}
const result = await fetcher();
this.cache.set(cacheKey, result, { ttl: ttlMs });
return result;
}
// Batch multiple requests into one
async batchGetAccounts(accountIds: string[]): Promise {
// Instead of N calls, use filter parameter
const filter = accountIds.map(id => `id:eq:${id}`).join(',or,');
return this.client.get(`/account/v1/accounts?filter=${filter}`);
}
// Use includes to reduce round trips
async getAccountComplete(accountId: string): Promise {
// Single call instead of 4
return this.client.get(
`/account/v1/accounts/${accountId}?include=policies,contacts,locations,activities`
);
}
// Compress large payloads
async postLargePayload(endpoint: string, data: any): Promise {
const compressed = await gzip(JSON.stringify(data));
return this.client.post(endpoint, compressed, {
headers: {
'Content-Encoding': 'gzip',
'Content-Type': 'application/json'
}
});
}
}
```
### Step 4: Storage Cost Optimization
```gosu
// Data archiving and retention
package gw.cost.storage
uses gw.api.database.Query
uses gw.api.util.Logger
uses gw.transaction.Transaction
class StorageOptimizer {
private static final var LOG = Logger.forCategory("StorageOptimizer")
// Archive old claims
static function archiveOldClaims(olderThanDays : int) {
var cutoffDate = Date.Today.addDays(-olderThanDays)
var claimsToArchive = Query.make(Claim)
.compare(Claim#CloseDate, LessThan, cutoffDate)
.compare(Claim#State, Equals, ClaimState.TC_CLOSED)
.select()
.toList()
LOG.info("Found ${claimsToArchive.Count} claims to archive")
claimsToArchive.batch(100).each(\batch -> {
Transaction.runWithNewBundle(\bundle -> {
batch.each(\claim -> {
var c = bundle.add(claim)
c.archiveToExternalStorage() // Custom archive implementation
})
})
})
}
// Purge old audit logs
static function purgeAuditLogs(olderThanDays : int) {
var cutoffDate = Date.Today.addDays(-olderThanDays)
var deleted = Query.make(AuditLog)
.compare(AuditLog#CreateTime, LessThan, cutoffDate)
.delete()
LOG.info("Purged ${deleted} audit log entries")
}
// Compress document attachments
static function compressAttachments(claim : Claim) {
claim.Documents.each(\doc -> {
if (doc.Size > 1024 * 1024 && !doc.IsCompressed) { // > 1MB
Transaction.runWithNewBundle(\bundle -> {
var d = bundle.add(doc)
d.compress()
})
}
})
}
// Generate storage report
static function getStorageReport() : StorageReport {
var report = new StorageReport()
report.TotalDocumentsMB = calculateTotalDocumentSize()
report.TotalAuditLogsMB = calculateAuditLogSize()
report.TotalHistoryMB = calculateHistorySize()
report.ArchivableClaims = Query.make(Claim)
.compare(Claim#CloseDate, LessThan, Date.Today.addYears(-2))
.select()
.Count
report.PurgeableAuditLogs = Query.make(AuditLog)
.compare(AuditLog#CreateTime, LessThan, Date.Today.addDays(-90))
.select()
.Count
return report
}
}
```
### Step 5: Compute Resource Right-Sizing
```typescript
// Resource utilization analysis
interface ResourceMetrics {
cpuUtilization: number[]; // Hourly samples
memoryUtilization: number[];
requestsPerSecond: number[];
timestamp: Date[];
}
class ResourceOptimizer {
async analyzeUtilization(days: number = 30): Promise {
const metrics = await this.getMetrics(days);
const cpuP95 = percentile(metrics.cpuUtilization, 95);
const memoryP95 = percentile(metrics.memoryUtilization, 95);
const rpsP95 = percentile(metrics.requestsPerSecond, 95);
const recommendations: ResourceRecommendation[] = [];
// CPU under-utilized
if (cpuP95 < 40) {
recommendations.push({
resource: 'CPU',
currentUtilization: cpuP95,
recommendation: 'Reduce CPU allocation',
potentialSavings: this.calculateCpuSavings(cpuP95)
});
}
// Memory over-provisioned
if (memoryP95 < 50) {
recommendations.push({
resource: 'Memory',
currentUtilization: memoryP95,
recommendation: 'Reduce memory allocation',
potentialSavings: this.calculateMemorySavings(memoryP95)
});
}
// Auto-scaling opportunities
const utilizationVariance = calculateVariance(metrics.cpuUtilization);
if (utilizationVariance > 0.3) {
recommendations.push({
resource: 'Compute',
recommendation: 'Enable auto-scaling',
reason: 'High utilization variance detected',
potentialSavings: this.calculateAutoScalingSavings(metrics)
});
}
return {
cpuP95,
memoryP95,
rpsP95,
recommendations
};
}
async implementAutoScaling(): Promise {
const config = {
minInstances: 2,
maxInstances: 10,
targetCpuUtilization: 70,
scaleUpCooldown: 300,
scaleDownCooldown: 600
};
await this.configureAutoScaling(config);
}
}
```
### Step 6: Cost Monitoring Dashboard
```typescript
// Cost monitoring and alerting
interface CostAlert {
threshold: number;
period: 'daily' | 'weekly' | 'monthly';
metric: string;
recipients: string[];
}
class CostMonitor {
private alerts: CostAlert[] = [];
addAlert(alert: CostAlert): void {
this.alerts.push(alert);
}
async checkAlerts(): Promise {
const notifications: AlertNotification[] = [];
for (const alert of this.alerts) {
const currentValue = await this.getCurrentValue(alert.metric, alert.period);
if (currentValue > alert.threshold) {
notifications.push({
alert,
currentValue,
exceededBy: ((currentValue - alert.threshold) / alert.threshold) * 100,
timestamp: new Date()
});
}
}
return notifications;
}
async generateReport(): Promise {
const currentMonth = await this.getMonthToDateCosts();
const previousMonth = await this.getPreviousMonthCosts();
return {
currentMonth,
previousMonth,
change: ((currentMonth.total - previousMonth.total) / previousMonth.total) * 100,
breakdown: {
licensing: currentMonth.licensing,
api: currentMonth.apiCalls,
storage: currentMonth.storage,
compute: currentMonth.compute
},
recommendations: await this.generateRecommendations()
};
}
}
// Example cost alert setup
const costMonitor = new CostMonitor();
costMonitor.addAlert({
threshold: 10000,
period: 'daily',
metric: 'api_calls',
recipients: ['devops@company.com']
});
costMonitor.addAlert({
threshold: 5000,
period: 'monthly',
metric: 'total_cost',
recipients: ['finance@company.com', 'cto@company.com']
});
```
## Cost Optimization Checklist
| Category | Action | Potential Savings |
|----------|--------|-------------------|
| Licensing | Deactivate inactive users | 10-30% |
| Licensing | Review license tiers | 5-15% |
| API | Implement caching | 20-50% |
| API | Use batch operations | 10-30% |
| Storage | Archive old data | 15-40% |
| Storage | Compress attachments | 10-20% |
| Compute | Right-size instances | 20-40% |
| Compute | Enable auto-scaling | 15-30% |
## Output
- Usage analysis report
- License optimization recommendations
- API efficiency improvements
- Storage reduction strategies
- Resource right-sizing configuration
## Resources
- [Guidewire Cloud Pricing](https://www.guidewire.com/pricing/)
- [Cloud Cost Management](https://docs.guidewire.com/cloud/)
## Next Steps
For architecture patterns, see `guidewire-reference-architecture`.