Class: RubySnowflake::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby_snowflake/client.rb,
lib/ruby_snowflake/client/http_connection_wrapper.rb,
lib/ruby_snowflake/client/key_pair_jwt_auth_manager.rb,
lib/ruby_snowflake/client/streaming_result_strategy.rb,
lib/ruby_snowflake/client/threaded_in_memory_strategy.rb,
lib/ruby_snowflake/client/single_thread_in_memory_strategy.rb

Defined Under Namespace

Classes: HttpConnectionWrapper, KeyPairJwtAuthManager, SingleThreadInMemoryStrategy, StreamingResultStrategy, ThreadedInMemoryStrategy

Constant Summary collapse

DEFAULT_LOGGER =
Logger.new(STDOUT)
DEFAULT_LOG_LEVEL =
Logger::INFO
DEFAULT_JWT_TOKEN_TTL =

seconds (59 min), this is the max supported by snowflake - 1 minute

3540
DEFAULT_CONNECTION_TIMEOUT =

seconds, how long for a thread to wait for a connection before erroring

60
DEFAULT_MAX_CONNECTIONS =

default maximum size of the http connection pool

16
DEFAULT_MAX_THREADS_PER_QUERY =

default maximum size of the thread pool on a single query

8
DEFAULT_THREAD_SCALE_FACTOR =

partition count factor for number of threads (i.e. 2 == once we have 4 partitions, spin up a second thread)

4
DEFAULT_HTTP_RETRIES =

how many times to retry common retryable HTTP responses (i.e. 429, 504)

2
DEFAULT_QUERY_TIMEOUT =

how long to wait to allow a query to complete, in seconds

600
OJ_OPTIONS =

10 minutes

{ :bigdecimal_load => :bigdecimal }.freeze
VALID_RESPONSE_CODES =
%w(200 202).freeze
POLLING_RESPONSE_CODE =
"202"
POLLING_INTERVAL =

seconds

2

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(uri, private_key, organization, account, user, default_warehouse, default_database, logger: DEFAULT_LOGGER, log_level: DEFAULT_LOG_LEVEL, jwt_token_ttl: DEFAULT_JWT_TOKEN_TTL, connection_timeout: DEFAULT_CONNECTION_TIMEOUT, max_connections: DEFAULT_MAX_CONNECTIONS, max_threads_per_query: DEFAULT_MAX_THREADS_PER_QUERY, thread_scale_factor: DEFAULT_THREAD_SCALE_FACTOR, http_retries: DEFAULT_HTTP_RETRIES, query_timeout: DEFAULT_QUERY_TIMEOUT) ⇒ Client

Returns a new instance of Client.



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/ruby_snowflake/client.rb', line 117

def initialize(
  uri, private_key, organization, , user, default_warehouse, default_database,
  logger: DEFAULT_LOGGER,
  log_level: DEFAULT_LOG_LEVEL,
  jwt_token_ttl: DEFAULT_JWT_TOKEN_TTL,
  connection_timeout: DEFAULT_CONNECTION_TIMEOUT,
  max_connections: DEFAULT_MAX_CONNECTIONS,
  max_threads_per_query: DEFAULT_MAX_THREADS_PER_QUERY,
  thread_scale_factor: DEFAULT_THREAD_SCALE_FACTOR,
  http_retries: DEFAULT_HTTP_RETRIES,
  query_timeout: DEFAULT_QUERY_TIMEOUT
)
  @base_uri = uri
  @key_pair_jwt_auth_manager =
    KeyPairJwtAuthManager.new(organization, , user, private_key, jwt_token_ttl)
  @default_warehouse = default_warehouse
  @default_database = default_database

  # set defaults for config settings
  @logger = logger
  @logger.level = log_level
  @connection_timeout = connection_timeout
  @max_connections = max_connections
  @max_threads_per_query = max_threads_per_query
  @thread_scale_factor = thread_scale_factor
  @http_retries = http_retries
  @query_timeout = query_timeout

  # Do NOT use normally, this exists for tests so we can reliably trigger the polling
  # response workflow from snowflake in tests
  @_enable_polling_queries = false
end

Instance Attribute Details

#connection_timeoutObject (readonly)

can’t be set after initialization



77
78
79
# File 'lib/ruby_snowflake/client.rb', line 77

def connection_timeout
  @connection_timeout
end

#http_retriesObject (readonly)

can’t be set after initialization



77
78
79
# File 'lib/ruby_snowflake/client.rb', line 77

def http_retries
  @http_retries
end

#loggerObject (readonly)

can’t be set after initialization



77
78
79
# File 'lib/ruby_snowflake/client.rb', line 77

def logger
  @logger
end

#max_connectionsObject (readonly)

can’t be set after initialization



77
78
79
# File 'lib/ruby_snowflake/client.rb', line 77

def max_connections
  @max_connections
end

#max_threads_per_queryObject (readonly)

can’t be set after initialization



77
78
79
# File 'lib/ruby_snowflake/client.rb', line 77

def max_threads_per_query
  @max_threads_per_query
end

#query_timeoutObject (readonly)

can’t be set after initialization



77
78
79
# File 'lib/ruby_snowflake/client.rb', line 77

def query_timeout
  @query_timeout
end

#thread_scale_factorObject (readonly)

can’t be set after initialization



77
78
79
# File 'lib/ruby_snowflake/client.rb', line 77

def thread_scale_factor
  @thread_scale_factor
end

Class Method Details

.from_env(logger: DEFAULT_LOGGER, log_level: DEFAULT_LOG_LEVEL, jwt_token_ttl: env_option("SNOWFLAKE_JWT_TOKEN_TTL", DEFAULT_JWT_TOKEN_TTL), connection_timeout: env_option("SNOWFLAKE_CONNECTION_TIMEOUT", DEFAULT_CONNECTION_TIMEOUT ), max_connections: env_option("SNOWFLAKE_MAX_CONNECTIONS", DEFAULT_MAX_CONNECTIONS ), max_threads_per_query: env_option("SNOWFLAKE_MAX_THREADS_PER_QUERY", DEFAULT_MAX_THREADS_PER_QUERY), thread_scale_factor: env_option("SNOWFLAKE_THREAD_SCALE_FACTOR", DEFAULT_THREAD_SCALE_FACTOR), http_retries: env_option("SNOWFLAKE_HTTP_RETRIES", DEFAULT_HTTP_RETRIES), query_timeout: env_option("SNOWFLAKE_QUERY_TIMEOUT", DEFAULT_QUERY_TIMEOUT)) ⇒ Object



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/ruby_snowflake/client.rb', line 79

def self.from_env(logger: DEFAULT_LOGGER,
                  log_level: DEFAULT_LOG_LEVEL,
                  jwt_token_ttl: env_option("SNOWFLAKE_JWT_TOKEN_TTL", DEFAULT_JWT_TOKEN_TTL),
                  connection_timeout: env_option("SNOWFLAKE_CONNECTION_TIMEOUT", DEFAULT_CONNECTION_TIMEOUT ),
                  max_connections: env_option("SNOWFLAKE_MAX_CONNECTIONS", DEFAULT_MAX_CONNECTIONS ),
                  max_threads_per_query: env_option("SNOWFLAKE_MAX_THREADS_PER_QUERY", DEFAULT_MAX_THREADS_PER_QUERY),
                  thread_scale_factor: env_option("SNOWFLAKE_THREAD_SCALE_FACTOR", DEFAULT_THREAD_SCALE_FACTOR),
                  http_retries: env_option("SNOWFLAKE_HTTP_RETRIES", DEFAULT_HTTP_RETRIES),
                  query_timeout: env_option("SNOWFLAKE_QUERY_TIMEOUT", DEFAULT_QUERY_TIMEOUT))
  private_key =
    if key = ENV["SNOWFLAKE_PRIVATE_KEY"]
      key
    elsif path = ENV["SNOWFLAKE_PRIVATE_KEY_PATH"]
      File.read(path)
    else
      raise MissingConfig.new({}), "Either ENV['SNOWFLAKE_PRIVATE_KEY'] or ENV['SNOWFLAKE_PRIVATE_KEY_PATH'] must be set"
    end

  new(
    ENV.fetch("SNOWFLAKE_URI"),
    private_key,
    ENV.fetch("SNOWFLAKE_ORGANIZATION"),
    ENV.fetch("SNOWFLAKE_ACCOUNT"),
    ENV.fetch("SNOWFLAKE_USER"),
    ENV["SNOWFLAKE_DEFAULT_WAREHOUSE"],
    ENV["SNOWFLAKE_DEFAULT_DATABASE"],
    logger: logger,
    log_level: log_level,
    jwt_token_ttl: jwt_token_ttl,
    connection_timeout: connection_timeout,
    max_connections: max_connections,
    max_threads_per_query: max_threads_per_query,
    thread_scale_factor: thread_scale_factor,
    http_retries: http_retries,
    query_timeout: query_timeout,
  )
end

Instance Method Details

#create_jwt_tokenObject

This method can be used to populate the JWT token used for authentication in tests that require time travel.



184
185
186
# File 'lib/ruby_snowflake/client.rb', line 184

def create_jwt_token
  @key_pair_jwt_auth_manager.jwt_token
end

#query(query, warehouse: nil, streaming: false, database: nil, schema: nil, bindings: nil) ⇒ Object Also known as: fetch



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/ruby_snowflake/client.rb', line 150

def query(query, warehouse: nil, streaming: false, database: nil, schema: nil, bindings: nil)
  warehouse ||= @default_warehouse
  database ||= @default_database

  query_start_time = Time.now.to_i
  response = nil
  connection_pool.with do |connection|
    request_body = {
      "warehouse" => warehouse&.upcase,
      "schema" => schema&.upcase,
      "database" =>  database&.upcase,
      "statement" => query,
      "bindings" => bindings
    }

    response = request_with_auth_and_headers(
      connection,
      Net::HTTP::Post,
      "/api/v2/statements?requestId=#{SecureRandom.uuid}&async=#{@_enable_polling_queries}",
      Oj.dump(request_body)
    )
  end
  retrieve_result_set(query_start_time, query, response, streaming)
end