๐Ÿ“… let's chat! explore the endless possibilities creating industries that don't exist. click here

guidewire-performance-tuning

Optimize Guidewire InsuranceSuite performance including query optimization, batch processing, caching, and JVM tuning. Trigger with phrases like "guidewire performance", "slow queries", "optimize policycenter", "batch processing", "query tuning". 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)

saas packs v1.0.0
View Plugin

Installation

This skill is included in the guidewire-pack plugin:

/plugin install guidewire-pack@claude-code-plugins-plus

Click to copy

Instructions

# Guidewire Performance Tuning ## Overview Optimize Guidewire InsuranceSuite performance through query optimization, efficient batch processing, caching strategies, and JVM configuration. ## Prerequisites - Access to Guidewire logs and metrics - Understanding of database query execution - Access to performance monitoring tools ## Performance Metrics Baseline | Metric | Target | Critical | |--------|--------|----------| | Page load time | < 2s | > 5s | | API response time (95th) | < 1s | > 3s | | Batch job completion | Within window | Exceeds window | | Database query time | < 100ms | > 1s | | Memory utilization | < 80% | > 95% | ## Instructions ### Step 1: Query Optimization ```gosu // Query optimization patterns package gw.performance uses gw.api.database.Query uses gw.api.database.Relop uses gw.api.util.Logger class QueryOptimization { private static final var LOG = Logger.forCategory("QueryOptimization") // BAD: Loads all data into memory static function getAllActivePoliciesBad() : List { return Query.make(Policy).select().toList() .where(\p -> p.Status == PolicyStatus.TC_INFORCE) } // GOOD: Filter at database level static function getAllActivePoliciesGood() : List { return Query.make(Policy) .compare(Policy#Status, Equals, PolicyStatus.TC_INFORCE) .select() .toList() } // BAD: N+1 query problem static function getAccountsWithPoliciesBad() : Map> { var accounts = Query.make(Account).select().toList() return accounts.mapToValue(\account -> account.Policies.toList()) // N additional queries! } // GOOD: Eager loading with join static function getAccountsWithPoliciesGood() : Map> { var policies = Query.make(Policy) .compare(Policy#Account, IsNotNull, null) .select() .toList() return policies.partition(\p -> p.Account) } // Pagination for large result sets static function getPoliciesPaginated(pageSize : int, pageNumber : int) : List { var offset = pageNumber * pageSize return Query.make(Policy) .compare(Policy#Status, Equals, PolicyStatus.TC_INFORCE) .select() .orderBy(\p -> p.IssueDate) .skip(offset) .take(pageSize) .toList() } // Use indexes effectively static function findPolicyByNumber(policyNumber : String) : Policy { // PolicyNumber is indexed - this will be fast return Query.make(Policy) .compare(Policy#PolicyNumber, Equals, policyNumber) .select() .AtMostOneRow } // Avoid wildcard searches when possible // BAD: Leading wildcard prevents index use static function searchPoliciesBad(searchTerm : String) : List { return Query.make(Policy) .contains(Policy#PolicyNumber, searchTerm, true) // Contains = %term% .select() .toList() } // GOOD: Use startsWith for index-friendly search static function searchPoliciesGood(searchTerm : String) : List { return Query.make(Policy) .startsWith(Policy#PolicyNumber, searchTerm, true) // StartsWith = term% .select() .toList() } } ``` ### Step 2: Batch Processing Optimization ```gosu // Efficient batch processing package gw.performance.batch uses gw.api.util.Logger uses gw.api.database.Query uses gw.transaction.Transaction class BatchProcessor { private static final var LOG = Logger.forCategory("BatchProcessor") private static final var BATCH_SIZE = 100 // Process large datasets in batches static function processAllPolicies(processor(policy : Policy)) { var processed = 0 var query = Query.make(Policy) .compare(Policy#Status, Equals, PolicyStatus.TC_INFORCE) var iterator = query.select().iterator() var batch = new ArrayList() while (iterator.hasNext()) { batch.add(iterator.next()) if (batch.size() >= BATCH_SIZE) { processBatch(batch, processor) processed += batch.size() batch.clear() LOG.info("Processed ${processed} policies") } } // Process remaining items if (!batch.Empty) { processBatch(batch, processor) processed += batch.size() } LOG.info("Batch processing complete: ${processed} total policies") } private static function processBatch(batch : List, processor(policy : Policy)) { Transaction.runWithNewBundle(\bundle -> { batch.each(\policy -> { var p = bundle.add(policy) processor(p) }) }) } // Parallel processing for independent operations static function processParallel( items : List, processor(item : T), threadCount : int = 4 ) { var executor = java.util.concurrent.Executors.newFixedThreadPool(threadCount) try { var futures = items.map(\item -> { executor.submit(\-> { try { processor(item) } catch (e : Exception) { LOG.error("Processing failed for item", e) } }) }) // Wait for all to complete futures.each(\f -> f.get()) } finally { executor.shutdown() } } } ``` ### Step 3: Caching Strategies ```gosu // Caching implementation package gw.performance.cache uses gw.api.util.Logger uses java.util.concurrent.ConcurrentHashMap uses java.util.concurrent.TimeUnit class CacheManager { private static final var LOG = Logger.forCategory("CacheManager") private static var _caches = new ConcurrentHashMap>() static function getCache(name : String, ttlSeconds : int = 300) : Cache { return _caches.computeIfAbsent(name, \n -> new Cache(ttlSeconds)) as Cache } static function clearAll() { _caches.values().each(\c -> c.clear()) } } class Cache { private var _data = new ConcurrentHashMap>() private var _ttlMs : long construct(ttlSeconds : int) { _ttlMs = TimeUnit.SECONDS.toMillis(ttlSeconds) } function get(key : K, loader() : V) : V { var entry = _data.get(key) if (entry != null && !entry.isExpired()) { return entry.Value } var value = loader() _data.put(key, new CacheEntry(value, _ttlMs)) return value } function invalidate(key : K) { _data.remove(key) } function clear() { _data.clear() } property get Size() : int { return _data.size() } } class CacheEntry { private var _value : V private var _expiresAt : long construct(value : V, ttlMs : long) { _value = value _expiresAt = System.currentTimeMillis() + ttlMs } property get Value() : V { return _value } function isExpired() : boolean { return System.currentTimeMillis() > _expiresAt } } // Usage example: Caching product lookup class ProductService { private static var _productCache = CacheManager.getCache("products", 3600) static function getProduct(code : String) : Product { return _productCache.get(code, \-> loadProductFromDatabase(code)) } private static function loadProductFromDatabase(code : String) : Product { return gw.api.productmodel.ProductLookup.getByCode(code) } } ``` ### Step 4: Database Connection Pool Tuning ```properties # database.properties - Connection pool optimization # Pool size - based on concurrent users # Formula: connections = (core_count * 2) + effective_spindle_count database.connection.pool.minSize=10 database.connection.pool.maxSize=50 database.connection.pool.initialSize=10 # Connection validation database.connection.validationQuery=SELECT 1 database.connection.testOnBorrow=true database.connection.testWhileIdle=true database.connection.timeBetweenEvictionRunsMillis=30000 # Statement caching database.preparedStatement.cacheSize=250 # Timeout settings database.connection.timeoutMs=30000 database.query.timeoutSeconds=60 ``` ### Step 5: JVM Tuning ```bash # JVM options for Guidewire Cloud applications # Production-optimized settings JAVA_OPTS=" # Memory settings -Xms4g -Xmx8g -XX:MetaspaceSize=512m -XX:MaxMetaspaceSize=1g # G1 Garbage Collector (recommended for heap > 4GB) -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:G1HeapRegionSize=16m -XX:+ParallelRefProcEnabled # GC logging -Xlog:gc*:file=/var/log/gc.log:time,uptime:filecount=5,filesize=100m # Performance flags -XX:+UseStringDeduplication -XX:+OptimizeStringConcat -XX:+UseCompressedOops # Debugging (remove in production) # -XX:+HeapDumpOnOutOfMemoryError # -XX:HeapDumpPath=/var/dumps/ " ``` ### Step 6: API Response Optimization ```typescript // Optimize API responses import { LRUCache } from 'lru-cache'; interface CacheConfig { maxSize: number; ttlMs: number; } class OptimizedApiClient { private cache: LRUCache; constructor(cacheConfig: CacheConfig = { maxSize: 500, ttlMs: 60000 }) { this.cache = new LRUCache({ max: cacheConfig.maxSize, ttl: cacheConfig.ttlMs }); } // Use field selection to reduce payload size async getPolicy(policyId: string, fields?: string[]): Promise { const cacheKey = `policy:${policyId}:${fields?.join(',') || 'all'}`; const cached = this.cache.get(cacheKey); if (cached) return cached; // Only request needed fields const fieldParam = fields?.length ? `?fields=${fields.join(',')}` : '?fields=policyNumber,effectiveDate,totalPremium,status'; const response = await this.client.get(`/policy/v1/policies/${policyId}${fieldParam}`); this.cache.set(cacheKey, response.data); return response.data; } // Use includes to reduce round trips async getAccountWithRelated(accountId: string): Promise { return this.client.get( `/account/v1/accounts/${accountId}?include=policies,contacts,locations` ); } // Parallel requests for independent data async getDashboardData(accountId: string): Promise { const [account, policies, claims, invoices] = await Promise.all([ this.getAccount(accountId), this.getPolicies(accountId), this.getClaims(accountId), this.getInvoices(accountId) ]); return { account, policies, claims, invoices }; } } ``` ### Step 7: Performance Monitoring ```gosu // Performance monitoring utilities package gw.performance.monitor uses gw.api.util.Logger uses java.util.concurrent.ConcurrentHashMap uses java.util.concurrent.atomic.AtomicLong class PerformanceMonitor { private static final var LOG = Logger.forCategory("PerformanceMonitor") private static var _metrics = new ConcurrentHashMap() static function time(operationName : String, operation() : T) : T { var startTime = System.nanoTime() var success = true try { return operation() } catch (e : Exception) { success = false throw e } finally { var duration = (System.nanoTime() - startTime) / 1_000_000.0 // ms recordMetric(operationName, duration, success) if (duration > 1000) { // Log slow operations LOG.warn("Slow operation: ${operationName} took ${duration}ms") } } } private static function recordMetric(name : String, durationMs : double, success : boolean) { var metrics = _metrics.computeIfAbsent(name, \n -> new OperationMetrics(n)) metrics.record(durationMs, success) } static function getMetrics() : Map { return new HashMap(_metrics) } static function reset() { _metrics.clear() } } class OperationMetrics { private var _name : String private var _count = new AtomicLong(0) private var _totalMs = new AtomicLong(0) private var _maxMs = new AtomicLong(0) private var _failures = new AtomicLong(0) construct(name : String) { _name = name } function record(durationMs : double, success : boolean) { _count.incrementAndGet() _totalMs.addAndGet(durationMs as long) // Update max (thread-safe) var currentMax = _maxMs.get() while (durationMs > currentMax) { if (_maxMs.compareAndSet(currentMax, durationMs as long)) { break } currentMax = _maxMs.get() } if (!success) { _failures.incrementAndGet() } } property get Name() : String { return _name } property get Count() : long { return _count.get() } property get AverageMs() : double { return _totalMs.get() / Math.max(_count.get(), 1) as double } property get MaxMs() : long { return _maxMs.get() } property get FailureRate() : double { return _failures.get() / Math.max(_count.get(), 1) as double } } ``` ## Performance Checklist | Area | Check | Status | |------|-------|--------| | Queries | All queries use indexes | [ ] | | Queries | No N+1 query patterns | [ ] | | Queries | Large results paginated | [ ] | | Batch | Appropriate batch sizes | [ ] | | Batch | Within maintenance windows | [ ] | | Caching | Frequently accessed data cached | [ ] | | Caching | Cache invalidation implemented | [ ] | | JVM | Memory settings optimized | [ ] | | JVM | GC logs analyzed | [ ] | ## Output - Optimized query patterns - Batch processing implementation - Caching layer configuration - JVM tuning parameters - Performance monitoring ## Resources - [Guidewire Performance Best Practices](https://docs.guidewire.com/education/) - [Database Query Optimization](https://docs.guidewire.com/cloud/) ## Next Steps For cost optimization, see `guidewire-cost-tuning`.

Skill file: plugins/saas-packs/guidewire-pack/skills/guidewire-performance-tuning/SKILL.md