11import React , { FC , useEffect , useRef } from 'react'
2+ import { useDispatch } from 'react-redux'
23import { useSelector } from 'react-redux'
34import { nanoid } from 'nanoid'
45import { parse , format_from_js_file } from '@influxdata/flux-lsp-browser'
@@ -9,14 +10,17 @@ import {FluxResult} from 'src/types/flows'
910import { propertyTime } from 'src/shared/utils/getMinDurationFromAST'
1011
1112// Constants
13+ import { FLUX_RESPONSE_BYTES_LIMIT } from 'src/shared/constants'
1214import { SELECTABLE_TIME_RANGES } from 'src/shared/constants/timeRanges'
1315import {
1416 RATE_LIMIT_ERROR_STATUS ,
1517 RATE_LIMIT_ERROR_TEXT ,
1618 GATEWAY_TIMEOUT_STATUS ,
1719 REQUEST_TIMEOUT_STATUS ,
1820} from 'src/cloud/constants'
19- import { isFlagEnabled } from 'src/shared/utils/featureFlag'
21+ import { isFlagEnabled , getFlagValue } from 'src/shared/utils/featureFlag'
22+ import { notify } from 'src/shared/actions/notifications'
23+ import { resultTooLarge } from 'src/shared/copy/notifications'
2024
2125// Types
2226import { CancellationError , File } from 'src/types'
@@ -57,6 +61,35 @@ interface RequestBody {
5761 extern ?: any
5862}
5963
64+ /*
65+ Given an arbitrary text chunk of a Flux CSV, trim partial lines off of the end
66+ of the text.
67+
68+ For example, given the following partial Flux response,
69+
70+ r,baz,3
71+ foo,bar,baz,2
72+ foo,bar,b
73+
74+ we want to trim the last incomplete line, so that the result is
75+
76+ r,baz,3
77+ foo,bar,baz,2
78+
79+ */
80+ const trimPartialLines = ( partialResp : string ) : string => {
81+ let i = partialResp . length - 1
82+
83+ while ( partialResp [ i ] !== '\n' ) {
84+ if ( i <= 0 ) {
85+ return partialResp
86+ }
87+
88+ i -= 1
89+ }
90+
91+ return partialResp . slice ( 0 , i + 1 )
92+ }
6093export interface QueryContextType {
6194 basic : ( text : string , override ?: QueryScope , options ?: QueryOptions ) => any
6295 query : (
@@ -485,6 +518,7 @@ const updateWindowPeriod = (
485518}
486519
487520export const QueryProvider : FC = ( { children} ) => {
521+ const dispatch = useDispatch ( )
488522 const pending = useRef ( { } as CancelMap )
489523 const org = useSelector ( getOrg )
490524
@@ -552,31 +586,34 @@ export const QueryProvider: FC = ({children}) => {
552586
553587 let csv = ''
554588 let bytesRead = 0
555-
589+ let didTruncate = false
556590 let read = await reader . read ( )
557591
592+ const BYTE_LIMIT =
593+ getFlagValue ( 'increaseCsvLimit' ) ?? FLUX_RESPONSE_BYTES_LIMIT
594+
558595 while ( ! read . done ) {
559- if ( ! pending . current [ id ] ) {
560- throw new CancellationError ( )
561- }
562596 const text = decoder . decode ( read . value )
563597
564598 bytesRead += read . value . byteLength
565599
566- csv += text
567- read = await reader . read ( )
600+ if ( bytesRead > BYTE_LIMIT ) {
601+ csv += trimPartialLines ( text )
602+ didTruncate = true
603+ break
604+ } else {
605+ csv += text
606+ read = await reader . read ( )
607+ }
568608 }
569609
570610 reader . cancel ( )
571- if ( pending . current [ id ] ) {
572- delete pending . current [ id ]
573- }
574611
575612 return {
576613 type : 'SUCCESS' ,
577614 csv,
578615 bytesRead,
579- didTruncate : false ,
616+ didTruncate,
580617 }
581618 }
582619
@@ -667,6 +704,10 @@ export const QueryProvider: FC = ({children}) => {
667704 throw new Error ( raw . message )
668705 }
669706
707+ if ( raw . didTruncate ) {
708+ dispatch ( notify ( resultTooLarge ( raw . bytesRead ) ) )
709+ }
710+
670711 return raw
671712 } )
672713 . then ( raw => fromFlux ( raw . csv ) )
0 commit comments