初始提交:OCI 面板后端(含 GenAI 网关一期)
This commit is contained in:
@@ -0,0 +1,285 @@
|
||||
package oci
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"oci-portal/internal/cache"
|
||||
)
|
||||
|
||||
// 读缓存 TTL 分级:过渡态资源短、准静态长(调研①方案 A)。
|
||||
// 实例列表 10s:前端 5s 自动刷新隔次命中,OCI 调用减半,状态延迟可控。
|
||||
const (
|
||||
cacheTTLInstances = 10 * time.Second
|
||||
cacheTTLVolatile = 30 * time.Second // 卷 / 挂载 / 网卡
|
||||
cacheTTLNetwork = 2 * time.Minute // VCN / 子网 / 安全列表
|
||||
cacheTTLStatic = 10 * time.Minute // 镜像 / 可用域
|
||||
)
|
||||
|
||||
// CachedClient 用进程内 TTL 缓存包装真实客户端,削减 OCI 读放大;
|
||||
// 写操作直通并失效同租户全部读缓存(粗粒度换正确性,重建仅一次回源)。
|
||||
// 未覆写的方法经嵌入接口直通。
|
||||
type CachedClient struct {
|
||||
Client
|
||||
store *cache.Cache
|
||||
}
|
||||
|
||||
// NewCachedClient 包装 inner;上限 4096 键(单键几 KB,整体几 MB 级)。
|
||||
func NewCachedClient(inner Client) *CachedClient {
|
||||
return &CachedClient{Client: inner, store: cache.New(4096)}
|
||||
}
|
||||
|
||||
// ckey 组缓存键;租户 OCID 在最前,写失效按前缀一锅端。
|
||||
func ckey(cred Credentials, parts ...string) string {
|
||||
return cred.TenancyOCID + "|" + strings.Join(parts, "|")
|
||||
}
|
||||
|
||||
// bust 写操作成功后失效该租户全部读缓存。
|
||||
func (c *CachedClient) bust(err error, cred Credentials) {
|
||||
if err == nil {
|
||||
c.store.DeletePrefix(cred.TenancyOCID + "|")
|
||||
}
|
||||
}
|
||||
|
||||
// cachedList 缓存切片结果;命中返回浅拷贝,防调用方排序共享底层数组。
|
||||
func cachedList[T any](c *CachedClient, key string, ttl time.Duration, fn func() ([]T, error)) ([]T, error) {
|
||||
v, err := cache.Do(c.store, key, ttl, fn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return slices.Clone(v), nil
|
||||
}
|
||||
|
||||
// ---- 读:按 TTL 分级缓存 ----
|
||||
|
||||
func (c *CachedClient) ListInstances(ctx context.Context, cred Credentials, region string) ([]Instance, error) {
|
||||
return cachedList(c, ckey(cred, "instances", region), cacheTTLInstances, func() ([]Instance, error) {
|
||||
return c.Client.ListInstances(ctx, cred, region)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CachedClient) ListImages(ctx context.Context, cred Credentials, q ImagesQuery) ([]Image, error) {
|
||||
return cachedList(c, ckey(cred, "images", q.Region, q.OperatingSystem, q.Shape), cacheTTLStatic, func() ([]Image, error) {
|
||||
return c.Client.ListImages(ctx, cred, q)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CachedClient) ListVCNs(ctx context.Context, cred Credentials, region string) ([]VCN, error) {
|
||||
return cachedList(c, ckey(cred, "vcns", region), cacheTTLNetwork, func() ([]VCN, error) {
|
||||
return c.Client.ListVCNs(ctx, cred, region)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CachedClient) ListSubnets(ctx context.Context, cred Credentials, region, vcnID string) ([]Subnet, error) {
|
||||
return cachedList(c, ckey(cred, "subnets", region, vcnID), cacheTTLNetwork, func() ([]Subnet, error) {
|
||||
return c.Client.ListSubnets(ctx, cred, region, vcnID)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CachedClient) ListSecurityLists(ctx context.Context, cred Credentials, region, vcnID string) ([]SecurityList, error) {
|
||||
return cachedList(c, ckey(cred, "seclists", region, vcnID), cacheTTLNetwork, func() ([]SecurityList, error) {
|
||||
return c.Client.ListSecurityLists(ctx, cred, region, vcnID)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CachedClient) ListAvailabilityDomains(ctx context.Context, cred Credentials, region string) ([]string, error) {
|
||||
return cachedList(c, ckey(cred, "ads", region), cacheTTLStatic, func() ([]string, error) {
|
||||
return c.Client.ListAvailabilityDomains(ctx, cred, region)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CachedClient) ListBootVolumes(ctx context.Context, cred Credentials, region, availabilityDomain string) ([]BootVolume, error) {
|
||||
return cachedList(c, ckey(cred, "bootvols", region, availabilityDomain), cacheTTLVolatile, func() ([]BootVolume, error) {
|
||||
return c.Client.ListBootVolumes(ctx, cred, region, availabilityDomain)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CachedClient) ListBlockVolumes(ctx context.Context, cred Credentials, region, availabilityDomain string) ([]BlockVolume, error) {
|
||||
return cachedList(c, ckey(cred, "blockvols", region, availabilityDomain), cacheTTLVolatile, func() ([]BlockVolume, error) {
|
||||
return c.Client.ListBlockVolumes(ctx, cred, region, availabilityDomain)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CachedClient) ListInstanceVnics(ctx context.Context, cred Credentials, region, instanceID string) ([]Vnic, error) {
|
||||
return cachedList(c, ckey(cred, "vnics", region, instanceID), cacheTTLVolatile, func() ([]Vnic, error) {
|
||||
return c.Client.ListInstanceVnics(ctx, cred, region, instanceID)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CachedClient) ListBootVolumeAttachments(ctx context.Context, cred Credentials, region, instanceID string) ([]BootVolumeAttachment, error) {
|
||||
return cachedList(c, ckey(cred, "bvattach", region, instanceID), cacheTTLVolatile, func() ([]BootVolumeAttachment, error) {
|
||||
return c.Client.ListBootVolumeAttachments(ctx, cred, region, instanceID)
|
||||
})
|
||||
}
|
||||
|
||||
func (c *CachedClient) ListVolumeAttachments(ctx context.Context, cred Credentials, region, instanceID string) ([]VolumeAttachment, error) {
|
||||
return cachedList(c, ckey(cred, "volattach", region, instanceID), cacheTTLVolatile, func() ([]VolumeAttachment, error) {
|
||||
return c.Client.ListVolumeAttachments(ctx, cred, region, instanceID)
|
||||
})
|
||||
}
|
||||
|
||||
// ---- 写:直通,成功后按租户失效 ----
|
||||
|
||||
func (c *CachedClient) LaunchInstance(ctx context.Context, cred Credentials, in CreateInstanceInput) (Instance, error) {
|
||||
out, err := c.Client.LaunchInstance(ctx, cred, in)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) UpdateInstance(ctx context.Context, cred Credentials, instanceID string, in UpdateInstanceInput) (Instance, error) {
|
||||
out, err := c.Client.UpdateInstance(ctx, cred, instanceID, in)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) TerminateInstance(ctx context.Context, cred Credentials, region, instanceID string, preserveBootVolume bool) error {
|
||||
err := c.Client.TerminateInstance(ctx, cred, region, instanceID, preserveBootVolume)
|
||||
c.bust(err, cred)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CachedClient) InstanceAction(ctx context.Context, cred Credentials, region, instanceID, action string) (Instance, error) {
|
||||
out, err := c.Client.InstanceAction(ctx, cred, region, instanceID, action)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) ChangeInstancePublicIP(ctx context.Context, cred Credentials, region, instanceID string) (string, error) {
|
||||
out, err := c.Client.ChangeInstancePublicIP(ctx, cred, region, instanceID)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) AddInstanceIpv6(ctx context.Context, cred Credentials, region, instanceID, address string) (string, error) {
|
||||
out, err := c.Client.AddInstanceIpv6(ctx, cred, region, instanceID, address)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) DeleteInstanceIpv6(ctx context.Context, cred Credentials, region, instanceID, address string) error {
|
||||
err := c.Client.DeleteInstanceIpv6(ctx, cred, region, instanceID, address)
|
||||
c.bust(err, cred)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CachedClient) CreateVCN(ctx context.Context, cred Credentials, in CreateVCNInput) (VCN, error) {
|
||||
out, err := c.Client.CreateVCN(ctx, cred, in)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) UpdateVCN(ctx context.Context, cred Credentials, region, vcnID, displayName string) (VCN, error) {
|
||||
out, err := c.Client.UpdateVCN(ctx, cred, region, vcnID, displayName)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) DeleteVCN(ctx context.Context, cred Credentials, region, vcnID string) error {
|
||||
err := c.Client.DeleteVCN(ctx, cred, region, vcnID)
|
||||
c.bust(err, cred)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CachedClient) EnableVCNIPv6(ctx context.Context, cred Credentials, region, vcnID string) ([]IPv6Step, error) {
|
||||
out, err := c.Client.EnableVCNIPv6(ctx, cred, region, vcnID)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) CreateSubnet(ctx context.Context, cred Credentials, in CreateSubnetInput) (Subnet, error) {
|
||||
out, err := c.Client.CreateSubnet(ctx, cred, in)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) UpdateSubnet(ctx context.Context, cred Credentials, region, subnetID, displayName string) (Subnet, error) {
|
||||
out, err := c.Client.UpdateSubnet(ctx, cred, region, subnetID, displayName)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) DeleteSubnet(ctx context.Context, cred Credentials, region, subnetID string) error {
|
||||
err := c.Client.DeleteSubnet(ctx, cred, region, subnetID)
|
||||
c.bust(err, cred)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CachedClient) CreateSecurityList(ctx context.Context, cred Credentials, in CreateSecurityListInput) (SecurityList, error) {
|
||||
out, err := c.Client.CreateSecurityList(ctx, cred, in)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) UpdateSecurityList(ctx context.Context, cred Credentials, securityListID string, in UpdateSecurityListInput) (SecurityList, error) {
|
||||
out, err := c.Client.UpdateSecurityList(ctx, cred, securityListID, in)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) DeleteSecurityList(ctx context.Context, cred Credentials, region, securityListID string) error {
|
||||
err := c.Client.DeleteSecurityList(ctx, cred, region, securityListID)
|
||||
c.bust(err, cred)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CachedClient) UpdateBootVolume(ctx context.Context, cred Credentials, bootVolumeID string, in UpdateBootVolumeInput) (BootVolume, error) {
|
||||
out, err := c.Client.UpdateBootVolume(ctx, cred, bootVolumeID, in)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) DeleteBootVolume(ctx context.Context, cred Credentials, region, bootVolumeID string) error {
|
||||
err := c.Client.DeleteBootVolume(ctx, cred, region, bootVolumeID)
|
||||
c.bust(err, cred)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CachedClient) AttachBootVolume(ctx context.Context, cred Credentials, region, instanceID, bootVolumeID string) (BootVolumeAttachment, error) {
|
||||
out, err := c.Client.AttachBootVolume(ctx, cred, region, instanceID, bootVolumeID)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) DetachBootVolume(ctx context.Context, cred Credentials, region, attachmentID string) error {
|
||||
err := c.Client.DetachBootVolume(ctx, cred, region, attachmentID)
|
||||
c.bust(err, cred)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CachedClient) ReplaceBootVolume(ctx context.Context, cred Credentials, region, instanceID, newBootVolumeID string) (BootVolumeAttachment, error) {
|
||||
out, err := c.Client.ReplaceBootVolume(ctx, cred, region, instanceID, newBootVolumeID)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) AttachVolume(ctx context.Context, cred Credentials, region, instanceID, volumeID string, readOnly bool) (VolumeAttachment, error) {
|
||||
out, err := c.Client.AttachVolume(ctx, cred, region, instanceID, volumeID, readOnly)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) DetachVolume(ctx context.Context, cred Credentials, region, attachmentID string) error {
|
||||
err := c.Client.DetachVolume(ctx, cred, region, attachmentID)
|
||||
c.bust(err, cred)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CachedClient) AttachVnic(ctx context.Context, cred Credentials, region, instanceID string, in AttachVnicInput) (Vnic, error) {
|
||||
out, err := c.Client.AttachVnic(ctx, cred, region, instanceID, in)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
|
||||
func (c *CachedClient) DetachVnic(ctx context.Context, cred Credentials, region, attachmentID string) error {
|
||||
err := c.Client.DetachVnic(ctx, cred, region, attachmentID)
|
||||
c.bust(err, cred)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *CachedClient) AddVnicIpv6(ctx context.Context, cred Credentials, region, vnicID, address string) (string, error) {
|
||||
out, err := c.Client.AddVnicIpv6(ctx, cred, region, vnicID, address)
|
||||
c.bust(err, cred)
|
||||
return out, err
|
||||
}
|
||||
Reference in New Issue
Block a user