aws 2025-09-12

Hi guys! I search in aws-api the support of mediaconvert but I not see it. Does aws-api support it?

It should work if you add https://github.com/cognitect-labs/aws-api/blob/e790cd736c3895ce83bf252740866868f3b1a5f5/latest-releases.edn#L672-L674 dependency and create a client with {:api :mediaconvert}

โœ… 1

Has anyone tried using aws-api within AWS Lambda with SnapStart enabled, where aws-api is called during priming? I noticed that the default credentials provider caches credentials, but these eventually expire. There is a refresh mechanism, but in the case of a process freeze & restore (as it works with SnapStart), the auto-refresh doesnโ€™t seem to work. I drafted a custom CredentialsProvider that uses a custom chain of providers (equivalents of the aws-api providers). It gives options for whether to cache credentials, whether to cache the resolved provider, and it allows refreshing credentials on Lambda restore. Has anyone already solved this problem? I might be a bit late checking, but better that than maintaining a custom solution.

Hmm, some time ago I did use aws-api in Lambda with Snapstart, I forget details, but have memory that aws-api should know to pick credentials from local metadata service endpoint, like it goes via with ECS https://docs.aws.amazon.com/lambda/latest/dg/snapstart-activate.html#snapstart-credentials (see the note in the link)

At development time, I was using aws-vault, which can run a "fake" local ECS metadata service, exposed the AWS_CONTAINER_CREDENTIALS_FULL_URI and AWS_CONTAINER_AUTHORIZATION_TOKEN aws-vault creates to the process I ran local development with (locally I was using jetty, what we ran in Lambda was a ring handler, with adapter to Lambda events, locally then used jetty)

This is not longer a problem to acquire credentials. aws-api does it automatically now, chaining a few providers until gets valid credentials. So locally stops finding env var credentials, on Lambda stops when detects ecs credentials. The problem I had was that I kept CredentialsProvider that was created before snapshot, and at the time Lambda was restored credentials the provider hold were expired. Initially, I experimented with this custom CredentialsProvider implementation that allows to refresh or reset credentials, but then I noticed that I also had to wind down some components as it doesn't make sense to have open ports when taking snapshot as they will be invalid at the restore (e.g. the http-client in aws-api). For now I decided to stop entire system before at the end of priming, and start the system after restore. That works pretty much fine even with default-credentials-provider from aws-api.

Ah yes, I forget already why I ran ecs metadata server locally, might be for other reasons (doubpting that it would have been for running same way as inside lambda env) I think at snapshot creation time I didn't do aws-api calls, but goood point on possibility of stale connection dating from snapshot time I think I had hikari+aws rds jdbc+postgresql driver configured so that they played nice with snapshot restore

๐Ÿ‘ 1

I'm not familiar with SnapStart but, as you probably have seen, the https://github.com/cognitect-labs/aws-api/blob/e790cd736c3895ce83bf252740866868f3b1a5f5/src/cognitect/aws/credentials.clj#L42-L71 depends on a ScheduledExecutorService task being executed a few minutes ahead of credentials expiration. If process freeze/restore breaks scheduled tasks, this won't work.

> refreshing credentials on Lambda restore How do you detect that?

Yes, I've read the refresh impl by now. > How do you detect that? SnapShot works based on CRaC, and it allows you to register two hooks: beforeCheckpoint and afterRestore. The first one is triggered before snapshot is taken (can be used for warming up JVM), the second after snapshot restore (so potentially invalid states could be repaired). What I did, is was adding yet another CredentialsProvider on top of the default, that can be refreshed.

๐Ÿ‘ 1

(defn- build-default-provider*
  [{:keys [;; config part
           cache-provider? cache-credentials? providers
           ;; extra
           http-client]}]
  (let [providers' (or providers [;; equivalents of cognitect providers, just without built-in credentials cache and refresh
                                  (environment-credentials-provider)
                                  (system-property-credentials-provider)
                                  (profile-credentials-provider)
                                  (container-credentials-provider http-client)
                                  (instance-profile-IMDSv2-credentials-provider http-client)
                                  #_{:clj-kondo/ignore [:deprecated-var]}
                                  (instance-profile-credentials-provider http-client)])
        creds-cache-fn (if cache-credentials? cached-credentials-with-auto-refresh identity)]
    (chain-credentials-provider-v2 {:providers (->> providers' (map creds-cache-fn))
                                    :cache-provider? cache-provider?})))

(defn default-credentials-provider-v2
  "Variant of `cognitect.aws.credentials/default-credentials-provider` allowing caching toggles."
  [{:keys [http-client cache-provider? cache-credentials?]}]
  (build-default-provider* {:http-client http-client
                            :cache-provider? cache-provider?
                            :cache-credentials? cache-credentials?}))

(defprotocol ReconfigurableCredentials
  (-reconfigure! [this cfg] "Replace internal credentials chain using cfg."))

(defprotocol ManuallyRefreshableCredentials
  (-refresh! [this] "Refresh "))

(defn reconfigurable-credentials-provider
  [{:keys [http-client cache-provider? cache-credentials?] :as cfg
    :or {cache-provider? true
         cache-credentials? true}}]
  (let [state* (atom {:cfg cfg
                      :prov (build-default-provider* cfg)})]
    (reify
      CredentialsProvider
      (fetch [_]
        (when-let [p (:prov @state*)]
          (fetch p)))

      ManuallyRefreshableCredentials
      (-refresh! [_]
        (let [[old _] (swap-vals! state* (fn [s]
                                           (let [cfg (:cfg s)
                                                 np (build-default-provider* cfg)]
                                             {:cfg cfg :prov np})))]
          (when-let [op (:prov old)]
            (try
              (-stop ^Stoppable op)
              (catch Throwable t
                (log/warn t "Error stopping previous credentials provider"))))
          :ok))

      ReconfigurableCredentials
      (-reconfigure! [_ new-cfg]
        (if (= new-cfg (:cfg @state*))
          :no-op
          (let [[old _] (swap-vals! state* (fn [old] (let [cfg (merge (:cfg old) new-cfg)
                                                           np (build-default-provider* cfg)]
                                                       {:cfg new-cfg :prov np})))]
            (when-let [op (:prov old)]
              (try
                (-stop ^Stoppable op)
                (catch Throwable t
                  (log/warn t "Error stopping previous credentials provider"))))
            :ok)))

      Stoppable
      (-stop [_]
        (let [[old _] (swap-vals! state* (fn [s] (assoc s :prov nil)))]
          (when-let [op (:prov old)]
            (try
              (-stop ^Stoppable op)
              (catch Throwable t
                (log/warn t "Error during provider stop"))))))
      #_:end)))

This could be actually reduced to just ManuallyRefreshableCredentials, as having both provider cache at chain and credentials cache doesn't harm

We do. We capture failing aws api requests on the theory that it loads enough of the classes. Don't need credentials that way